diff --git a/.claude/settings.json b/.claude/settings.json index c60bf4afb1..416bb2617f 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -29,6 +29,7 @@ "Bash(grep:*)", "Bash(mv:*)", "Bash(source .venv/bin/activate)", + "Bash(source tox.venv/bin/activate:*)", "Bash(tox:*)", "Bash(tox.venv/bin/tox:*)", "Bash(.tox/*/bin/python:*)", diff --git a/.github/workflows/ai-integration-test.yml b/.github/workflows/ai-integration-test.yml index 65d57caba7..6827ebb7d2 100644 --- a/.github/workflows/ai-integration-test.yml +++ b/.github/workflows/ai-integration-test.yml @@ -19,12 +19,12 @@ jobs: steps: - name: Setup Python - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: python-version: 3.14t - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: '20' @@ -34,7 +34,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} - name: Run Python SDK Tests - uses: getsentry/testing-ai-sdk-integrations@6b1f51ec8af03e19087df452b426aa7e46d2b20a + uses: getsentry/testing-ai-sdk-integrations@1dd9ee2a2d821f41473fc90809a758e8394c689c env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/changelog-preview.yml b/.github/workflows/changelog-preview.yml index 3788b29609..0854abe5da 100644 --- a/.github/workflows/changelog-preview.yml +++ b/.github/workflows/changelog-preview.yml @@ -15,5 +15,5 @@ permissions: jobs: changelog-preview: - uses: getsentry/craft/.github/workflows/changelog-preview.yml@v2 + uses: getsentry/craft/.github/workflows/changelog-preview.yml@97d0c4286f32a80d09c8b89366d762fecc3e27b6 # v2 secrets: inherit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c56d8375c..c7d3a95915 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,10 @@ on: pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + permissions: contents: read @@ -24,7 +28,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: python-version: 3.14 @@ -39,11 +43,11 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: python-version: 3.12 - name: Setup build cache - uses: actions/cache@v5 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 id: build_cache with: path: ${{ env.CACHED_BUILD_PATHS }} @@ -54,7 +58,7 @@ jobs: # This will also trigger "make dist" that creates the Python packages make aws-lambda-layer - name: Upload Python Packages - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: artifact-build_lambda_layer path: | @@ -68,7 +72,7 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: python-version: 3.12 @@ -76,7 +80,7 @@ jobs: make apidocs cd docs/_build && zip -r gh-pages ./ - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: artifact-docs path: | diff --git a/.github/workflows/enforce-license-compliance.yml b/.github/workflows/enforce-license-compliance.yml index 7cee2720e5..fece653550 100644 --- a/.github/workflows/enforce-license-compliance.yml +++ b/.github/workflows/enforce-license-compliance.yml @@ -18,6 +18,6 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Enforce License Compliance' - uses: getsentry/action-enforce-license-compliance@main + uses: getsentry/action-enforce-license-compliance@48236a773346cb6552a7bda1ee370d2797365d87 # main with: fossa_api_key: ${{ secrets.FOSSA_API_KEY }} diff --git a/.github/workflows/release-comment-issues.yml b/.github/workflows/release-comment-issues.yml index e18aeab155..0203ff59ed 100644 --- a/.github/workflows/release-comment-issues.yml +++ b/.github/workflows/release-comment-issues.yml @@ -33,7 +33,7 @@ jobs: && !contains(steps.get_version.outputs.version, 'a') && !contains(steps.get_version.outputs.version, 'b') && !contains(steps.get_version.outputs.version, 'rc') - uses: getsentry/release-comment-issues-gh-action@v1 + uses: getsentry/release-comment-issues-gh-action@52e08022ca721e701515ede89edd224b63b180eb # v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} version: ${{ steps.get_version.outputs.version }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b2a935fcea..307f9ab745 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,16 +22,16 @@ jobs: steps: - name: Get auth token id: token - uses: actions/create-github-app-token@f8d387b68d61c58ab83c6c016672934102569859 # v2 + uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1 with: app-id: ${{ vars.SENTRY_RELEASE_BOT_CLIENT_ID }} private-key: ${{ secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY }} - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: token: ${{ steps.token.outputs.token }} fetch-depth: 0 - name: Prepare release - uses: getsentry/craft@013a7b2113c2cac0ff32d5180cfeaefc7c9ce5b6 # v2 + uses: getsentry/craft@ba01e596c4a4c07692f0de10b0d4fe05f3dd0292 # v2.25.2 env: GITHUB_TOKEN: ${{ steps.token.outputs.token }} with: diff --git a/.github/workflows/test-integrations-agents.yml b/.github/workflows/test-integrations-agents.yml index a05649a5f0..efa0b9480c 100644 --- a/.github/workflows/test-integrations-agents.yml +++ b/.github/workflows/test-integrations-agents.yml @@ -41,8 +41,8 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} @@ -74,11 +74,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All Agents tests passed diff --git a/.github/workflows/test-integrations-ai-workflow.yml b/.github/workflows/test-integrations-ai-workflow.yml index 7cd4cb86df..d7025ce067 100644 --- a/.github/workflows/test-integrations-ai-workflow.yml +++ b/.github/workflows/test-integrations-ai-workflow.yml @@ -41,8 +41,8 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} @@ -78,11 +78,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All AI Workflow tests passed diff --git a/.github/workflows/test-integrations-ai.yml b/.github/workflows/test-integrations-ai.yml index 0b305a3775..6d09c0ef5f 100644 --- a/.github/workflows/test-integrations-ai.yml +++ b/.github/workflows/test-integrations-ai.yml @@ -41,8 +41,8 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} @@ -94,11 +94,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All AI tests passed diff --git a/.github/workflows/test-integrations-cloud.yml b/.github/workflows/test-integrations-cloud.yml index d57034d4e3..c61d0a49d8 100644 --- a/.github/workflows/test-integrations-cloud.yml +++ b/.github/workflows/test-integrations-cloud.yml @@ -45,8 +45,8 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} @@ -90,11 +90,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All Cloud tests passed diff --git a/.github/workflows/test-integrations-common.yml b/.github/workflows/test-integrations-common.yml index 9b333435bd..c96d1adc0c 100644 --- a/.github/workflows/test-integrations-common.yml +++ b/.github/workflows/test-integrations-common.yml @@ -41,8 +41,8 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} @@ -70,11 +70,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All Common tests passed diff --git a/.github/workflows/test-integrations-dbs.yml b/.github/workflows/test-integrations-dbs.yml index c27d728b98..15bee0cf2a 100644 --- a/.github/workflows/test-integrations-dbs.yml +++ b/.github/workflows/test-integrations-dbs.yml @@ -59,14 +59,14 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} allow-prereleases: true - name: "Setup ClickHouse Server" - uses: getsentry/action-clickhouse-in-ci@v1.7 + uses: getsentry/action-clickhouse-in-ci@5dc8a6a50d689bd6051db0241f34849e5a36490b # v1.7 - name: Setup Test Env run: | pip install "coverage[toml]" tox @@ -110,11 +110,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All DBs tests passed diff --git a/.github/workflows/test-integrations-flags.yml b/.github/workflows/test-integrations-flags.yml index cd20a6ec5e..f3cdf1f143 100644 --- a/.github/workflows/test-integrations-flags.yml +++ b/.github/workflows/test-integrations-flags.yml @@ -41,8 +41,8 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} @@ -82,11 +82,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All Flags tests passed diff --git a/.github/workflows/test-integrations-gevent.yml b/.github/workflows/test-integrations-gevent.yml index 525140dfa7..1ecdac2953 100644 --- a/.github/workflows/test-integrations-gevent.yml +++ b/.github/workflows/test-integrations-gevent.yml @@ -41,8 +41,8 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} @@ -70,11 +70,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All Gevent tests passed diff --git a/.github/workflows/test-integrations-graphql.yml b/.github/workflows/test-integrations-graphql.yml index 322a95ff54..01df240ad0 100644 --- a/.github/workflows/test-integrations-graphql.yml +++ b/.github/workflows/test-integrations-graphql.yml @@ -41,8 +41,8 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} @@ -82,11 +82,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All GraphQL tests passed diff --git a/.github/workflows/test-integrations-mcp.yml b/.github/workflows/test-integrations-mcp.yml index 4b576a897f..de70b5c04e 100644 --- a/.github/workflows/test-integrations-mcp.yml +++ b/.github/workflows/test-integrations-mcp.yml @@ -41,8 +41,8 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} @@ -74,11 +74,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All MCP tests passed diff --git a/.github/workflows/test-integrations-misc.yml b/.github/workflows/test-integrations-misc.yml index 021d6cda79..ee1ec4628a 100644 --- a/.github/workflows/test-integrations-misc.yml +++ b/.github/workflows/test-integrations-misc.yml @@ -41,8 +41,8 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} @@ -102,11 +102,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All Misc tests passed diff --git a/.github/workflows/test-integrations-network.yml b/.github/workflows/test-integrations-network.yml index ee4579f50f..e93c60056a 100644 --- a/.github/workflows/test-integrations-network.yml +++ b/.github/workflows/test-integrations-network.yml @@ -41,8 +41,8 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} @@ -61,6 +61,10 @@ jobs: run: | set -x # print commands that are executed ./scripts/runtox.sh "py${{ matrix.python-version }}-httpx" + - name: Test pyreqwest + run: | + set -x # print commands that are executed + ./scripts/runtox.sh "py${{ matrix.python-version }}-pyreqwest" - name: Test requests run: | set -x # print commands that are executed @@ -78,11 +82,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All Network tests passed diff --git a/.github/workflows/test-integrations-tasks.yml b/.github/workflows/test-integrations-tasks.yml index bab5ddf335..49910d3c72 100644 --- a/.github/workflows/test-integrations-tasks.yml +++ b/.github/workflows/test-integrations-tasks.yml @@ -41,16 +41,16 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} allow-prereleases: true - name: Start Redis - uses: supercharge/redis-github-action@v2 + uses: supercharge/redis-github-action@87f27ff1ab2d9e62db54b11ee5e7f78ff18f8933 # v2 - name: Install Java - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: distribution: 'temurin' java-version: '21' @@ -105,11 +105,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All Tasks tests passed diff --git a/.github/workflows/test-integrations-web-1.yml b/.github/workflows/test-integrations-web-1.yml index 82632632e7..362b98dad9 100644 --- a/.github/workflows/test-integrations-web-1.yml +++ b/.github/workflows/test-integrations-web-1.yml @@ -59,8 +59,8 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} @@ -100,11 +100,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All Web 1 tests passed diff --git a/.github/workflows/test-integrations-web-2.yml b/.github/workflows/test-integrations-web-2.yml index 9dec6bff24..69076bf16b 100644 --- a/.github/workflows/test-integrations-web-2.yml +++ b/.github/workflows/test-integrations-web-2.yml @@ -41,8 +41,8 @@ jobs: # Use Docker container only for Python 3.6 container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 if: ${{ matrix.python-version != '3.6' }} with: python-version: ${{ matrix.python-version }} @@ -106,11 +106,12 @@ jobs: coverage xml - name: Parse and Upload Coverage if: ${{ !cancelled() }} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: ${{ secrets.GITHUB_TOKEN }} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true check_required_tests: name: All Web 2 tests passed diff --git a/.github/workflows/update-tox.yml b/.github/workflows/update-tox.yml index b4463105ae..105377cfd2 100644 --- a/.github/workflows/update-tox.yml +++ b/.github/workflows/update-tox.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Setup Python - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: python-version: 3.14t @@ -54,7 +54,7 @@ jobs: echo "date=$DATE" >> $GITHUB_OUTPUT - name: Create pull request - uses: actions/github-script@v8 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const branchName = '${{ steps.create-branch.outputs.branch_name }}'; diff --git a/.github/workflows/validate-pr.yml b/.github/workflows/validate-pr.yml new file mode 100644 index 0000000000..10fe894067 --- /dev/null +++ b/.github/workflows/validate-pr.yml @@ -0,0 +1,16 @@ +name: Validate PR + +on: + pull_request_target: + types: [opened, reopened] + +jobs: + validate-pr: + runs-on: ubuntu-24.04 + permissions: + pull-requests: write + steps: + - uses: getsentry/github-workflows/validate-pr@71588ddf95134f804e82c5970a8098588e2eaecd + with: + app-id: ${{ vars.SDK_MAINTAINER_BOT_APP_ID }} + private-key: ${{ secrets.SDK_MAINTAINER_BOT_PRIVATE_KEY }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 9abbbc4225..8892b397dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,152 @@ # Changelog +## 2.58.0 + +### New Features ✨ + +- (ai) Redact base64 data URLs in image_url content blocks by @ericapisani in [#5953](https://github.com/getsentry/sentry-python/pull/5953) +- (integrations) Instrument pyreqwest tracing by @servusdei2018 in [#5682](https://github.com/getsentry/sentry-python/pull/5682) +- (litellm) Add async callbacks by @alexander-alderman-webb in [#5969](https://github.com/getsentry/sentry-python/pull/5969) + +### Bug Fixes πŸ› + +#### Anthropic + +- Capture exceptions for `stream()` calls by @alexander-alderman-webb in [#5950](https://github.com/getsentry/sentry-python/pull/5950) +- Stop setting transaction status when child span fails by @alexander-alderman-webb in [#5717](https://github.com/getsentry/sentry-python/pull/5717) +- Only finish relevant spans in .create() patches by @alexander-alderman-webb in [#5716](https://github.com/getsentry/sentry-python/pull/5716) + +#### Pydantic Ai + +- Adapt import for new library versions by @alexander-alderman-webb in [#5984](https://github.com/getsentry/sentry-python/pull/5984) +- Use first-class hooks when available by @alexander-alderman-webb in [#5947](https://github.com/getsentry/sentry-python/pull/5947) + +#### Other + +- (huggingface_hub) Stop setting transaction status when a child span fails by @Zenithatic in [#5952](https://github.com/getsentry/sentry-python/pull/5952) +- (litellm) Avoid double span exits when streaming by @alexander-alderman-webb in [#5933](https://github.com/getsentry/sentry-python/pull/5933) +- (wsgi) Respect HTTP_X_FORWARDED_PROTO in request.url construction by @sl0thentr0py in [#5963](https://github.com/getsentry/sentry-python/pull/5963) + +### Internal Changes πŸ”§ + +#### Litellm + +- Replace mocks with `httpx` types in rate-limit test by @alexander-alderman-webb in [#5975](https://github.com/getsentry/sentry-python/pull/5975) +- Replace mocks with `httpx` types in embedding tests by @alexander-alderman-webb in [#5970](https://github.com/getsentry/sentry-python/pull/5970) +- Replace mocks with `httpx` types in nonstreaming `completion()` tests by @alexander-alderman-webb in [#5937](https://github.com/getsentry/sentry-python/pull/5937) +- Remove dead attributes by @alexander-alderman-webb in [#5985](https://github.com/getsentry/sentry-python/pull/5985) + +#### Other + +- (ai) Remove `gen_ai.tool.type` span attribute by @ericapisani in [#5964](https://github.com/getsentry/sentry-python/pull/5964) +- (anthropic) Separate sync and async .create() patches by @alexander-alderman-webb in [#5715](https://github.com/getsentry/sentry-python/pull/5715) +- (openai) Split token counting by API for easier deprecation by @ericapisani in [#5930](https://github.com/getsentry/sentry-python/pull/5930) +- (openai-agents) Remove error attributes by @alexander-alderman-webb in [#5986](https://github.com/getsentry/sentry-python/pull/5986) +- (opentelemetry) Ignore mypy error by @alexander-alderman-webb in [#5927](https://github.com/getsentry/sentry-python/pull/5927) +- πŸ€– Update test matrix with new releases (04/13) by @github-actions in [#5983](https://github.com/getsentry/sentry-python/pull/5983) +- Fix license metadata in setup.py by @sl0thentr0py in [#5934](https://github.com/getsentry/sentry-python/pull/5934) +- Update validate-pr workflow by @stephanie-anderson in [#5931](https://github.com/getsentry/sentry-python/pull/5931) + +### Other + +- Handle `None` span context in the span processor and pin tokenizers version for anthropic tests on Python 3.8 by @alexander-alderman-webb in [#5967](https://github.com/getsentry/sentry-python/pull/5967) + +## 2.57.0 + +### New Features ✨ + +#### Langchain + +- Set `gen_ai.operation.name` and `gen_ai.pipeline.name` on LLM spans by @ericapisani in [#5849](https://github.com/getsentry/sentry-python/pull/5849) +- Broaden AI provider detection beyond OpenAI and Anthropic by @ericapisani in [#5707](https://github.com/getsentry/sentry-python/pull/5707) +- Update LLM span operation to `gen_ai.generate_text` by @ericapisani in [#5796](https://github.com/getsentry/sentry-python/pull/5796) + +#### Other + +- Add experimental async transport by @BYK in [#5646](https://github.com/getsentry/sentry-python/pull/5646) + + See https://github.com/getsentry/sentry-python/discussions/5919 for details. + +### Bug Fixes πŸ› + +#### Openai + +- Only wrap types with `_iterator` for streamed responses by @alexander-alderman-webb in [#5917](https://github.com/getsentry/sentry-python/pull/5917) +- Always set `gen_ai.response.streaming` for Responses by @alexander-alderman-webb in [#5697](https://github.com/getsentry/sentry-python/pull/5697) +- Simplify Responses input handling by @alexander-alderman-webb in [#5695](https://github.com/getsentry/sentry-python/pull/5695) +- Use `max_output_tokens` for Responses API by @alexander-alderman-webb in [#5693](https://github.com/getsentry/sentry-python/pull/5693) +- Always set `gen_ai.response.streaming` for Completions by @alexander-alderman-webb in [#5692](https://github.com/getsentry/sentry-python/pull/5692) +- Simplify Completions input handling by @alexander-alderman-webb in [#5690](https://github.com/getsentry/sentry-python/pull/5690) +- Simplify embeddings input handling by @alexander-alderman-webb in [#5688](https://github.com/getsentry/sentry-python/pull/5688) + +#### Other + +- (google-genai) Guard response extraction by @alexander-alderman-webb in [#5869](https://github.com/getsentry/sentry-python/pull/5869) +- Add cycle detection to exceptions_from_error by @ericapisani in [#5880](https://github.com/getsentry/sentry-python/pull/5880) + +### Internal Changes πŸ”§ + +#### Ai + +- Remove unused GEN_AI_PIPELINE operation constant by @ericapisani in [#5886](https://github.com/getsentry/sentry-python/pull/5886) +- Rename generate_text to text_completion by @ericapisani in [#5885](https://github.com/getsentry/sentry-python/pull/5885) + +#### Langchain + +- Add text completion test by @alexander-alderman-webb in [#5740](https://github.com/getsentry/sentry-python/pull/5740) +- Add tool execution test by @alexander-alderman-webb in [#5739](https://github.com/getsentry/sentry-python/pull/5739) +- Add basic agent test with Responses call by @alexander-alderman-webb in [#5726](https://github.com/getsentry/sentry-python/pull/5726) +- Replace mocks with `httpx` types by @alexander-alderman-webb in [#5724](https://github.com/getsentry/sentry-python/pull/5724) +- Consolidate span origin assertion by @alexander-alderman-webb in [#5723](https://github.com/getsentry/sentry-python/pull/5723) +- Consolidate available tools assertion by @alexander-alderman-webb in [#5721](https://github.com/getsentry/sentry-python/pull/5721) + +#### Openai + +- Replace mocks with httpx types for streaming Responses by @alexander-alderman-webb in [#5882](https://github.com/getsentry/sentry-python/pull/5882) +- Replace mocks with httpx types for streaming Completions by @alexander-alderman-webb in [#5879](https://github.com/getsentry/sentry-python/pull/5879) +- Move input handling code into API-specific functions by @alexander-alderman-webb in [#5687](https://github.com/getsentry/sentry-python/pull/5687) + +#### Other + +- (asyncpg) Normalize query whitespace in integration by @ericapisani in [#5855](https://github.com/getsentry/sentry-python/pull/5855) +- Exclude compromised litellm versions by @alexander-alderman-webb in [#5876](https://github.com/getsentry/sentry-python/pull/5876) + + +## 2.56.0 + +### New Features ✨ + +- (asgi) Add option to disable suppressing chained exceptions by @alexander-alderman-webb in [#5714](https://github.com/getsentry/sentry-python/pull/5714) +- (logging) Separate ignore lists for events/breadcrumbs and sentry logs by @sl0thentr0py in [#5698](https://github.com/getsentry/sentry-python/pull/5698) + +### Bug Fixes πŸ› + +#### Anthropic + +- Set exception info on streaming span when applicable by @alexander-alderman-webb in [#5683](https://github.com/getsentry/sentry-python/pull/5683) +- Patch `AsyncStream.close()` and `AsyncMessageStream.close()` to finish spans by @alexander-alderman-webb in [#5675](https://github.com/getsentry/sentry-python/pull/5675) +- Patch `Stream.close()` and `MessageStream.close()` to finish spans by @alexander-alderman-webb in [#5674](https://github.com/getsentry/sentry-python/pull/5674) + +#### Other + +- (starlette) Catch Jinja2Templates ImportError by @alexander-alderman-webb in [#5741](https://github.com/getsentry/sentry-python/pull/5741) + +### Documentation πŸ“š + +- Add note on AI PRs to CONTRIBUTING.md by @sentrivana in [#5696](https://github.com/getsentry/sentry-python/pull/5696) + +### Internal Changes πŸ”§ + +- Pin GitHub Actions to full-length commit SHAs by @joshuarli in [#5781](https://github.com/getsentry/sentry-python/pull/5781) +- Add `-latest` alias for each integration test suite by @sentrivana in [#5706](https://github.com/getsentry/sentry-python/pull/5706) +- Use date-based branch names for toxgen PRs by @sentrivana in [#5704](https://github.com/getsentry/sentry-python/pull/5704) +- πŸ€– Update test matrix with new releases (03/19) by @github-actions in [#5703](https://github.com/getsentry/sentry-python/pull/5703) +- Add client report tests for span streaming by @sentrivana in [#5677](https://github.com/getsentry/sentry-python/pull/5677) + +### Other + +- Update CHANGELOG.md by @sentrivana in [#5685](https://github.com/getsentry/sentry-python/pull/5685) + ## 2.55.0 ### New Features ✨ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f9831d8a01..6149d86336 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,23 +4,64 @@ We welcome contributions to `sentry-python` by the community. This file outlines the process to contribute to the SDK itself. For contributing to the documentation, please see the [Contributing to Docs](https://docs.sentry.io/contributing/) page. +## Table of Contents + +- [How to Report a Problem](#how-to-report-a-problem) +- [Submitting Changes](#submitting-changes) +- [Development Environment](#development-environment) +- [Running Tests](#running-tests) +- [Debugging](#debugging) +- [Adding a New Integration](#adding-a-new-integration) +- [Releasing a New Version](#releasing-a-new-version) +- [Contributing to Sentry AWS Lambda Layer](#contributing-to-sentry-aws-lambda-layer) + ## How to Report a Problem Please search the [issue tracker](https://github.com/getsentry/sentry-python/issues) before creating a new issue (a problem or an improvement request). Please also ask in our [Sentry Community on Discord](https://discord.com/invite/Ww9hbqr) before submitting a new issue. There are a ton of great people in our Discord community ready to help you! ## Submitting Changes +### Before You Start + +1. **Find or create an issue.** Every contribution must be tied to a GitHub issue. If one doesn't exist, open one describing the problem or feature. +2. **Discuss your approach with a maintainer.** Comment on the issue and wait for a maintainer to respond before you start working. This avoids wasted effort on both sides. +3. **Check the assignee.** If the issue is already assigned to someone else, coordinate with them in the issue before starting work. + +PRs that don't meet these requirements will be automatically closed. See [Automated Checks](#automated-checks) below. + +### Making Your Contribution + - Fork the `sentry-python` repo and prepare your changes. - Add tests for your changes to `tests/`. - Run tests and make sure all of them pass. -- Submit a pull request, referencing any issues your changes address. Please follow our [commit message format](https://develop.sentry.dev/commit-messages/#commit-message-format) when naming your pull request. +- Submit a pull request, referencing the issue(s) your changes address. Please follow our [commit message format](https://develop.sentry.dev/commit-messages/#commit-message-format) when naming your pull request. + +### Pull Request Requirements -We will review your pull request as soon as possible. Thank you for contributing! +All PRs must be created as **drafts**. Non-draft PRs will be automatically converted to draft. Mark your PR as "Ready for review" once: + +- CI passes +- The PR description is complete (what, why, and links to relevant issues) +- You've personally reviewed your own changes + +A PR should do one thing well. Don't mix functional changes with unrelated refactors or cleanup. Smaller, focused PRs are easier to review, reason about, and revert if needed. + +For the full set of PR standards, see the [code submission standard](https://develop.sentry.dev/sdk/getting-started/standards/code-submission/#pull-requests). ### AI Use You are welcome to use whatever tools you prefer for making a contribution. However, any changes you propose have to be reviewed and tested by you, a human, first, before you submit a pull request with them for the Sentry team to review. If we feel like that didn't happen, we will close the PR outright. For example, we won't review visibly AI-generated PRs from an agent instructed to look for and "fix" open issues in the repo. +### Automated Checks + +To maintain the quality of contributions, we use automated workflows that enforce the following rules for PRs from non-maintainers: + +- **Issue reference required.** Your PR body must reference a GitHub issue in the `getsentry` organization (e.g. `#123`, `getsentry/sentry#456`, or a full GitHub issue URL). +- **Prior discussion required.** The referenced issue must show a conversation between you and a maintainer. Opening the issue counts as participation β€” but a maintainer must have also responded. +- **Respect existing assignees.** If the referenced issue is assigned to someone other than you, the PR will be closed. Coordinate in the issue first. + +PRs that don't meet these criteria are automatically closed and labeled `violating-contribution-guidelines`. If your PR was closed by mistake, comment on the issue to discuss with a maintainer and then open a new PR. + ## Development Environment ### Set up Python diff --git a/docs/conf.py b/docs/conf.py index da8917f86d..59010b9a2e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,7 +31,7 @@ copyright = "2019-{}, Sentry Team and Contributors".format(datetime.now().year) author = "Sentry Team and Contributors" -release = "2.55.0" +release = "2.58.0" version = ".".join(release.split(".")[:2]) # The short X.Y version. diff --git a/scripts/populate_tox/config.py b/scripts/populate_tox/config.py index c6921754b4..457b52dbb2 100644 --- a/scripts/populate_tox/config.py +++ b/scripts/populate_tox/config.py @@ -18,6 +18,9 @@ "deps": { "*": ["pytest-asyncio"], "<0.50": ["httpx<0.28.0"], + # tokenizers dropped Python 3.8 support, but didn't update package metadata. + # https://github.com/huggingface/tokenizers/commit/f4c9fd7f402fc794df8f1b547a95ee5305f9fe62 + "py3.8": ["tokenizers<0.20.4"], }, "python": ">=3.8", }, @@ -122,7 +125,8 @@ "pytest-asyncio", "python-multipart", "requests", - "anyio<4", + "anyio>=3,<5", + "jinja2", ], # There's an incompatibility between FastAPI's TestClient, which is # actually Starlette's TestClient, which is actually httpx's Client. @@ -132,6 +136,7 @@ # 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"], }, }, @@ -170,7 +175,8 @@ "httpx": { "package": "httpx", "deps": { - "*": ["anyio<4.0.0"], + "*": ["anyio>=3,<5"], + "<0.24": ["anyio<4"], ">=0.16,<0.17": ["pytest-httpx==0.10.0"], ">=0.17,<0.19": ["pytest-httpx==0.12.0"], ">=0.19,<0.21": ["pytest-httpx==0.14.0"], @@ -231,6 +237,9 @@ }, "litellm": { "package": "litellm", + "deps": { + "*": ["anthropic", "google-genai", "pytest-asyncio"], + }, }, "litestar": { "package": "litestar", @@ -305,6 +314,14 @@ "deps": { "*": ["pytest-asyncio"], }, + "python": ">=3.10", + }, + "pyreqwest": { + "package": "pyreqwest", + "deps": { + "*": ["pytest-asyncio"], + }, + "python": ">=3.11", }, "pymongo": { "package": "pymongo", diff --git a/scripts/populate_tox/package_dependencies.jsonl b/scripts/populate_tox/package_dependencies.jsonl index b1288ac680..2fe885fc96 100644 --- a/scripts/populate_tox/package_dependencies.jsonl +++ b/scripts/populate_tox/package_dependencies.jsonl @@ -1,40 +1,44 @@ -{"name": "anthropic", "version": "0.86.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/63/5f/67db29c6e5d16c8c9c4652d3efb934d89cb750cad201539141781d8eae14/anthropic-0.86.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/26/c4/97ecde8b1e74f67b8598c57c6fccf6df86ea7861ed29da84629cdbba76c4/jiter-0.13.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}]} -{"name": "ariadne", "version": "1.0.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/f5/6f/2d6499510949717f040e8e4108bdfdeebb2305264c1f5986994765079c2a/ariadne-1.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/86/41/cb887d9afc5dabd78feefe6ccbaf83ff423c206a7a1b7aeeac05120b2125/graphql_core-3.2.8-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}]} -{"name": "boto3", "version": "1.42.71", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/e2/b6/b0b93090cfc3fdbdb21a0b18961508678a2b36a42e2b3a90994ac34e102c/boto3-1.42.71-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/86/b3/b970b62963b2391d10cd29402d3338bf49730e083aa9b2a688c8bf76af08/botocore-1.42.71-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}]} -{"name": "cohere", "version": "5.20.7", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/9d/86/dc991a75e3b9c2007b90dbfaf7f36fdb2457c216f799e26ce0474faf0c1f/cohere-5.20.7-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/65/8b/fa2d3287fd2267be6261d0177c6809a7fa12c5600ddb33490c8dc29e77b2/fastavro-1.12.1.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ec/74/2bc951622e2dbba1af9a460d93c51d15e458becd486e62c29cc0ccb08178/huggingface_hub-1.5.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f2/8a/08a24b6c6f52b5d26848c16e4b6d790bb810d1bf62c3505bed179f7032d3/hf_xet-1.3.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1c/12/709ea261f2bf91ef0a26a9eed20f2623227a8ed85610c1e54c5805692ecb/types_requests-2.32.4.20260107-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f9/0b/de6f54d4a8bedfe8645c41497f3c18d749f0bd3218170c667bf4b81d0cdd/filelock-3.25.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}]} -{"name": "django", "version": "5.2.12", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/4e/32/4b144e125678efccf5d5b61581de1c4088d6b0286e46096e3b8de0d556c8/django-5.2.12-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}]} -{"name": "django", "version": "6.0.3", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/72/b1/23f2556967c45e34d3d3cf032eb1bd3ef925ee458667fb99052a0b3ea3a6/django-6.0.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}]} +{"name": "anthropic", "version": "0.94.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/0c/ac/7185750e8688f6ff79b0e3d6a61372c88b81ba81fcda8798c70598e18aca/anthropic-0.94.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/05/57/7dbc0ffbbb5176a27e3518716608aa464aee2e2887dc938f0b900a120449/jiter-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}]} +{"name": "ariadne", "version": "1.0.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/ad/25/086e35461dc8c9e87daaaeb370ccab36a6e37153ed30471482e3ab95d35d/ariadne-1.0.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/c9/584bc9651441b4ba60cc4d557d8a547b5aff901af35bda3a4ee30c819b82/starlette-1.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/86/41/cb887d9afc5dabd78feefe6ccbaf83ff423c206a7a1b7aeeac05120b2125/graphql_core-3.2.8-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}]} +{"name": "ariadne", "version": "1.1.0a2", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/4e/88/09c93f85859531c0e356e255590579c854f62f4ffd6dcf4214d6b6d79bb1/ariadne-1.1.0a2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5e/3f/7f4c3becebb10bd5669acb60bd024b8493e47475d8bf8a66b54e49784e5c/graphql_core-3.3.0a12-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}]} +{"name": "boto3", "version": "1.42.88", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/0a/2b/8bfddb39a19f5fbc16a869f1a394771e6223f07160dbc0ff6b38e05ea0ae/boto3-1.42.88-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/46/ad14e41245adb8b0c83663ba13e822b68a0df08999dd250e75b0750fdf6c/botocore-1.42.88-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}]} +{"name": "cohere", "version": "5.21.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/0a/50/5538f02ec6d10fbb84f29c1b18c68ff2a03d7877926a80275efdf8755a9f/cohere-5.21.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/65/8b/fa2d3287fd2267be6261d0177c6809a7fa12c5600ddb33490c8dc29e77b2/fastavro-1.12.1.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/8c/c7a33f3efaa8d6a5bc40e012e5ecc2d72c2e6124550ca9085fe0ceed9993/huggingface_hub-1.10.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b5/9c/defb6cb1de28bccb7bd8d95f6e60f72a3d3fa4cb3d0329c26fb9a488bfe7/hf_xet-1.4.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/90/b8/78fd6c037de4788c040fdd323b3369804400351b7827473920f6c1d03c10/types_requests-2.33.0.20260408-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d5/1f/5f4a3cd9e4440e9d9bc78ad0a91a1c8d46b4d429d5239ebe6793c9fe5c41/fsspec-2026.3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}]} +{"name": "cohere", "version": "6.1.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/9e/b4/00c2f9f8387a2e77faf8410210466c46d55dd30a0388de41c54441b148fb/cohere-6.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/65/8b/fa2d3287fd2267be6261d0177c6809a7fa12c5600ddb33490c8dc29e77b2/fastavro-1.12.1.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/8c/c7a33f3efaa8d6a5bc40e012e5ecc2d72c2e6124550ca9085fe0ceed9993/huggingface_hub-1.10.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b5/9c/defb6cb1de28bccb7bd8d95f6e60f72a3d3fa4cb3d0329c26fb9a488bfe7/hf_xet-1.4.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/90/b8/78fd6c037de4788c040fdd323b3369804400351b7827473920f6c1d03c10/types_requests-2.33.0.20260408-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d5/1f/5f4a3cd9e4440e9d9bc78ad0a91a1c8d46b4d429d5239ebe6793c9fe5c41/fsspec-2026.3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}]} +{"name": "django", "version": "5.2.13", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/59/b1/51ab36b2eefcf8cdb9338c7188668a157e29e30306bfc98a379704c9e10d/django-5.2.13-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}]} +{"name": "django", "version": "6.0.4", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/e9/47/3d61d611609764aa71a37f7037b870e7bfb22937366974c4fd46cada7bab/django-6.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl"}}]} {"name": "dramatiq", "version": "2.1.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/c2/91/422960c8c415fd31ca1519d71d6f7e4bcabb2cdcc5872f784467e9fe7237/dramatiq-2.1.0-py3-none-any.whl"}}]} -{"name": "fastapi", "version": "0.135.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/e4/72/42e900510195b23a56bde950d26a51f8b723846bfcaa0286e90287f0422b/fastapi-0.135.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}]} -{"name": "fastmcp", "version": "0.1.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/f5/07/bc69e65b45d638822190bce0defb497a50d240291b8467cb79078d0064b7/fastmcp-0.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fd/d9/eaa1f80170d2b7c5ba23f3b59f766f3a0bb41155fbc32a69adfa1adaaef9/mcp-1.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/96/7f/832f015020844a8b8f7a9cbc103dd76ba8e3875004c41e08440ea3a2b41a/sse_starlette-3.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d5/91/9b286ab899c008c2cb05e8be99814807e7fbbd33f0c0c960470826e5ac82/typer-0.23.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}]} -{"name": "fastmcp", "version": "0.4.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/79/0b/008a340435fe8f0879e9d608f48af2737ad48440e09bd33b83b3fd03798b/fastmcp-0.4.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fd/d9/eaa1f80170d2b7c5ba23f3b59f766f3a0bb41155fbc32a69adfa1adaaef9/mcp-1.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/96/7f/832f015020844a8b8f7a9cbc103dd76ba8e3875004c41e08440ea3a2b41a/sse_starlette-3.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d5/91/9b286ab899c008c2cb05e8be99814807e7fbbd33f0c0c960470826e5ac82/typer-0.23.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}]} -{"name": "fastmcp", "version": "1.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/b9/bf/0a77688242f30f81e3633d3765289966d9c7e408f9dcb4928a85852b9fde/fastmcp-1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fd/d9/eaa1f80170d2b7c5ba23f3b59f766f3a0bb41155fbc32a69adfa1adaaef9/mcp-1.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/96/7f/832f015020844a8b8f7a9cbc103dd76ba8e3875004c41e08440ea3a2b41a/sse_starlette-3.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d5/91/9b286ab899c008c2cb05e8be99814807e7fbbd33f0c0c960470826e5ac82/typer-0.23.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ef/45/615f5babd880b4bd7d405cc0dc348234c5ffb6ed1ea33e152ede08b2072d/rich-14.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}]} -{"name": "flask", "version": "2.3.3", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/fd/56/26f0be8adc2b4257df20c1c4260ddd0aa396cf8e75d90ab2f7ff99bc34f9/flask-2.3.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ad/e4/8d97cca767bcc1be76d16fb76951608305561c6e056811587f36cb1316a8/werkzeug-3.1.5-py3-none-any.whl"}}]} -{"name": "flask", "version": "3.1.3", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"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"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ad/e4/8d97cca767bcc1be76d16fb76951608305561c6e056811587f36cb1316a8/werkzeug-3.1.5-py3-none-any.whl"}}]} -{"name": "google-genai", "version": "1.55.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/3e/86/a5a8e32b2d40b30b5fb20e7b8113fafd1e38befa4d1801abd5ce6991065a/google_genai-1.55.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/eb/c6c2478d8a8d633460be40e2a8a6f8f429171997a35a96f81d3b680dec83/google_auth-2.49.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/440635fc093b8d7347502a377031f9605a1039c958f3cd18dcacffb37743/charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/44/b5/a96872e5184f354da9c84ae119971a0a4c221fe9b27a4d94bd43f2596727/pyasn1-0.6.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}]} -{"name": "google-genai", "version": "1.68.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/84/de/7d3ee9c94b74c3578ea4f88d45e8de9405902f857932334d81e89bce3dfa/google_genai-1.68.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/eb/c6c2478d8a8d633460be40e2a8a6f8f429171997a35a96f81d3b680dec83/google_auth-2.49.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/31/93/8878be7569f87b14f1d52032946131bcb6ebbd8af3e20446bc04053dc3f1/charset_normalizer-3.4.6-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}]} -{"name": "gql", "version": "4.3.0b0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/3a/9a/0f888771634de03e679e3de0bbbe7580966d8ee3854ee6bf6c24e85a8330/gql-4.3.0b0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c3/a3/b14060e541cd3a94da2b2a89f0e7815284b52010aa3adb06c07a3b7c23b5/graphql_core-3.3.0a11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5d/9a/2f65743589809af4d0a6d3aa749343c4b5f4c380cc24a8e94a3c6625a808/yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl"}}]} +{"name": "fastapi", "version": "0.135.3", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/84/a4/5caa2de7f917a04ada20018eccf60d6cc6145b0199d55ca3711b0fc08312/fastapi-0.135.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/c9/584bc9651441b4ba60cc4d557d8a547b5aff901af35bda3a4ee30c819b82/starlette-1.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}]} +{"name": "fastmcp", "version": "0.1.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/f5/07/bc69e65b45d638822190bce0defb497a50d240291b8467cb79078d0064b7/fastmcp-0.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9c/46/f6b4ad632c67ef35209a66127e4bddc95759649dd595f71f13fba11bdf9a/mcp-1.27.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/22/f1925cdda983ab66fc8ec6ec8014b959262747e58bdca26a4e3d1da29d56/python_multipart-0.0.26-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f8/7f/3de5402f39890ac5660b86bcf5c03f9d855dad5c4ed764866d7b592b46fd/sse_starlette-3.3.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/c9/584bc9651441b4ba60cc4d557d8a547b5aff901af35bda3a4ee30c819b82/starlette-1.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/23/a5bbd9600dd607411fa644c06ff4951bec3a4d82c4b852374024359c19c0/uvicorn-0.44.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}]} +{"name": "fastmcp", "version": "0.4.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/79/0b/008a340435fe8f0879e9d608f48af2737ad48440e09bd33b83b3fd03798b/fastmcp-0.4.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9c/46/f6b4ad632c67ef35209a66127e4bddc95759649dd595f71f13fba11bdf9a/mcp-1.27.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/22/f1925cdda983ab66fc8ec6ec8014b959262747e58bdca26a4e3d1da29d56/python_multipart-0.0.26-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f8/7f/3de5402f39890ac5660b86bcf5c03f9d855dad5c4ed764866d7b592b46fd/sse_starlette-3.3.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/c9/584bc9651441b4ba60cc4d557d8a547b5aff901af35bda3a4ee30c819b82/starlette-1.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/23/a5bbd9600dd607411fa644c06ff4951bec3a4d82c4b852374024359c19c0/uvicorn-0.44.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}]} +{"name": "fastmcp", "version": "1.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/b9/bf/0a77688242f30f81e3633d3765289966d9c7e408f9dcb4928a85852b9fde/fastmcp-1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9c/46/f6b4ad632c67ef35209a66127e4bddc95759649dd595f71f13fba11bdf9a/mcp-1.27.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/22/f1925cdda983ab66fc8ec6ec8014b959262747e58bdca26a4e3d1da29d56/python_multipart-0.0.26-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f8/7f/3de5402f39890ac5660b86bcf5c03f9d855dad5c4ed764866d7b592b46fd/sse_starlette-3.3.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/c9/584bc9651441b4ba60cc4d557d8a547b5aff901af35bda3a4ee30c819b82/starlette-1.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/23/a5bbd9600dd607411fa644c06ff4951bec3a4d82c4b852374024359c19c0/uvicorn-0.44.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}]} +{"name": "flask", "version": "2.3.3", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/fd/56/26f0be8adc2b4257df20c1c4260ddd0aa396cf8e75d90ab2f7ff99bc34f9/flask-2.3.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}]} +{"name": "flask", "version": "3.1.3", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}]} +{"name": "google-genai", "version": "1.57.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/d6/02/858bdae08e2184b6afe0b18bc3113318522c9cf326a5a1698055edd31f88/google_genai-1.57.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}]} +{"name": "google-genai", "version": "1.72.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/9f/3d/9f70246114cdf56a2615a40428ced08bc844f5a26247fe812b2f0dd4eaca/google_genai-1.72.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}]} +{"name": "gql", "version": "4.3.0b2", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/16/e4/2986c73d428485c2b88f80c3e20d25396bb94beae6a1f845dbb3d6787087/gql-4.3.0b2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5e/3f/7f4c3becebb10bd5669acb60bd024b8493e47475d8bf8a66b54e49784e5c/graphql_core-3.3.0a12-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/f1/dab7ac5e7306fb79c0190766a3c00b4cb8d09a1f390ded68c85a5934faf5/yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl"}}]} {"name": "huey", "version": "2.6.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/1a/34/fae9ac8f1c3a552fd3f7ff652b94c78d219dedc5fce0c0a4232457760a00/huey-2.6.0-py3-none-any.whl"}}]} -{"name": "huggingface_hub", "version": "1.7.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/6f/75/ca21955d6117a394a482c7862ce96216239d0e3a53133ae8510727a8bcfa/huggingface_hub-1.7.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bf/e3/8933c073186849b5e06762aa89847991d913d10a95d1603eb7f2c3834086/hf_xet-1.4.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl"}}, {"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"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}]} -{"name": "langchain", "version": "1.2.12", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/ca/51/09bb1cfb0b57ae9440ca56cc576e4dc792f83d030eef7637d2c516dcb0a0/langchain-1.2.12-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/aa/cb/8704b2a22c0987627ed29464d23a45fb15e10a28fb482f4d84c3bddcbf27/langchain_core-1.2.19-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/52/38/3117cd90325635893a76132cdae74f5b1f53c93c33b3dc6124521cec9825/langgraph-1.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/65/4c/09a4a0c42f5d2fc38d6c4d67884788eff7fd2cfdf367fdf7033de908b4c0/langgraph_checkpoint-4.0.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/41/ec966424ad3f2ed3996d24079d3342c8cd6c0bd0653c12b2a917a685ec6c/langgraph_prebuilt-1.0.8-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/13/c8/b8d15d4b9a320a3f57a851030a371066b91dbd1420f097d3d0338da9adc9/langgraph_sdk-0.3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/34/31/62689d57f4d25792bd6a3c05c868771899481be2f3e31f9e71d31e1ac4ab/langsmith-0.7.17-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"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"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7b/d1/38a573f0c631c062cf42fa1f5d021d4dd3c31fb23e4376e4b56b0c9fbbed/uuid_utils-0.14.1.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/53/45/b268004f745ede84e5798b48ee12b05129d19235d0e15267aa57dcdb400b/orjson-3.11.7.tar.gz"}}, {"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"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/440635fc093b8d7347502a377031f9605a1039c958f3cd18dcacffb37743/charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/8c/63/8ffc2cc97e811c0ca5d00ab36604b3ea6f4254f20b7bc658ca825ce6c954/xxhash-3.6.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}]} -{"name": "langgraph", "version": "0.6.11", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/df/94/430f0341c5c2fe3e3b9f5ab2622f35e2bda12c4a7d655c519468e853d1b0/langgraph-0.6.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/48/e3/616e3a7ff737d98c1bbb5700dd62278914e2a9ded09a79a1fa93cf24ce12/langgraph_checkpoint-3.0.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/8e/d1/e4727f4822943befc3b7046f79049b1086c9493a34b4d44a1adf78577693/langgraph_prebuilt-0.6.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/6b/c9/bf2bff18f85bb7973fa5280838580049574bd7649c36e3dd346c49304997/langgraph_sdk-0.2.15-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/8c/a5/678ab0e5cc57794f20ae5ed12c1442506ef1108c9434f950aebc6044e5a3/langchain_core-1.2.12-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ce/87/6f2b008a456b4f5fd0fb1509bb7e1e9368c1a0c9641a535f224a9ddc10f3/langsmith-0.7.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/57/7c/3a926e847516e67bc6838634f2e54e24381105b4e80f9338dc35cca0086b/uuid_utils-0.14.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/53/45/b268004f745ede84e5798b48ee12b05129d19235d0e15267aa57dcdb400b/orjson-3.11.7.tar.gz"}}, {"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"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/55/f4/2a7c3c68e564a099becfa44bb3d398810cc0ff6749b0d3cb8ccb93f23c14/xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}]} -{"name": "launchdarkly-server-sdk", "version": "9.15.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/79/0e/fb5954448bcdef93475d14d2500edd9730c6d7dc02a3bb9732c602ac2981/launchdarkly_server_sdk-9.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/54/c6/c0816382050a97ebf0e4590e0adf93a317e7e64333eed4467b1081b261d7/launchdarkly_eventsource-1.5.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}]} -{"name": "openai", "version": "2.29.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/d0/b1/35b6f9c8cf9318e3dbb7146cc82dab4cf61182a8d5406fc9b50864362895/openai-2.29.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/62/92/1661d8b9fd6a3d7a2d89831db26fe3c1509a287d83ad7838831c7b7a5c7e/jiter-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}]} -{"name": "openai-agents", "version": "0.12.5", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/9f/d2/ac4a43bcf20563a19ad78ea3457d234faf6023e9f0a7a634e43c47799f58/openai_agents-0.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fd/d9/eaa1f80170d2b7c5ba23f3b59f766f3a0bb41155fbc32a69adfa1adaaef9/mcp-1.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d0/b1/35b6f9c8cf9318e3dbb7146cc82dab4cf61182a8d5406fc9b50864362895/openai-2.29.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/26/c4/97ecde8b1e74f67b8598c57c6fccf6df86ea7861ed29da84629cdbba76c4/jiter-0.13.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/440635fc093b8d7347502a377031f9605a1039c958f3cd18dcacffb37743/charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1c/12/709ea261f2bf91ef0a26a9eed20f2623227a8ed85610c1e54c5805692ecb/types_requests-2.32.4.20260107-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c2/c7/736e00ebf39ed81d75544c0da6ef7b0998f8201b369acf842f9a90dc8fce/rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/e2/b8cff57a67dddf9a464d7e943218e031617fb3ddc133aeeb0602ff5f6c85/sse_starlette-3.3.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0a/89/f8827ccff89c1586027a105e5630ff6139a64da2515e24dafe860bd9ae4d/uvicorn-0.42.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}]} -{"name": "openai-agents", "version": "0.8.4", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/55/dc/10df015aebb0797a8367aab65200ac4f5221df20bbae76930f5b6ac8e001/openai_agents-0.8.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fd/d9/eaa1f80170d2b7c5ba23f3b59f766f3a0bb41155fbc32a69adfa1adaaef9/mcp-1.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c6/2e/3f73e8ca53718952222cacd0cf7eecc9db439d020f0c1fe7ae717e4e199a/openai-2.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/62/92/1661d8b9fd6a3d7a2d89831db26fe3c1509a287d83ad7838831c7b7a5c7e/jiter-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c5/60/3a621758945513adfd4db86827a5bafcc615f913dbd0b4c2ed64a65731be/charset_normalizer-3.4.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1c/12/709ea261f2bf91ef0a26a9eed20f2623227a8ed85610c1e54c5805692ecb/types_requests-2.32.4.20260107-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/6f/01/c26ce75ba460d5cd503da9e13b21a33804d38c2165dec7b716d06b13010c/pyjwt-2.11.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/61/28/8cb142d3fe80c4a2d8af54ca0b003f47ce0ba920974e7990fa6e016402d1/sse_starlette-3.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/e4/d04a086285c20886c0daad0e026f250869201013d18f81d9ff5eada73a88/uvicorn-0.41.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}]} +{"name": "huggingface_hub", "version": "1.10.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/83/8c/c7a33f3efaa8d6a5bc40e012e5ecc2d72c2e6124550ca9085fe0ceed9993/huggingface_hub-1.10.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b5/9c/defb6cb1de28bccb7bd8d95f6e60f72a3d3fa4cb3d0329c26fb9a488bfe7/hf_xet-1.4.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d5/1f/5f4a3cd9e4440e9d9bc78ad0a91a1c8d46b4d429d5239ebe6793c9fe5c41/fsspec-2026.3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}]} +{"name": "langchain", "version": "1.2.15", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/3f/e8/a3b8cb0005553f6a876865073c81ef93bd7c5b18381bcb9ba4013af96ebc/langchain-1.2.15-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a8/92/32f785f077c7e898da97064f113c73fbd9ad55d1e2169cf3a391b183dedb/langchain_core-1.2.28-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/71/e6/b36ecdb3ff4ba9a290708d514bae89ebbe2f554b6abbe4642acf3fddbe51/langgraph-1.1.6-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/65/4c/09a4a0c42f5d2fc38d6c4d67884788eff7fd2cfdf367fdf7033de908b4c0/langgraph_checkpoint-4.0.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1d/a2/8368ac187b75e7f9d938ca075d34f116683f5cfc48d924029ee79aea147b/langgraph_prebuilt-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fe/ef/64d64e9f8eea47ce7b939aa6da6863b674c8d418647813c20111645fcc62/langgraph_sdk-0.3.13-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/37/19/96250cf58070c5563446651b03bb76c2eb5afbf08e754840ab639532d8c6/langsmith-0.7.30-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7b/d1/38a573f0c631c062cf42fa1f5d021d4dd3c31fb23e4376e4b56b0c9fbbed/uuid_utils-0.14.1.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9d/1b/2024d06792d0779f9dbc51531b61c24f76c75b9f4ce05e6f3377a1814cea/orjson-3.11.8.tar.gz"}}, {"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"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/55/f4/2a7c3c68e564a099becfa44bb3d398810cc0ff6749b0d3cb8ccb93f23c14/xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}]} +{"name": "langgraph", "version": "0.6.11", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/df/94/430f0341c5c2fe3e3b9f5ab2622f35e2bda12c4a7d655c519468e853d1b0/langgraph-0.6.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/48/e3/616e3a7ff737d98c1bbb5700dd62278914e2a9ded09a79a1fa93cf24ce12/langgraph_checkpoint-3.0.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/8e/d1/e4727f4822943befc3b7046f79049b1086c9493a34b4d44a1adf78577693/langgraph_prebuilt-0.6.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/6b/c9/bf2bff18f85bb7973fa5280838580049574bd7649c36e3dd346c49304997/langgraph_sdk-0.2.15-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a8/92/32f785f077c7e898da97064f113c73fbd9ad55d1e2169cf3a391b183dedb/langchain_core-1.2.28-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/07/02e16ed01e04a374e644b575638ec7987ae846d25ad97bcc9945a3ee4b0e/jsonpatch-1.33-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/37/19/96250cf58070c5563446651b03bb76c2eb5afbf08e754840ab639532d8c6/langsmith-0.7.30-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7b/d1/38a573f0c631c062cf42fa1f5d021d4dd3c31fb23e4376e4b56b0c9fbbed/uuid_utils-0.14.1.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9e/6a/a83720e953b1682d2d109d3c2dbb0bc9bf28cc1cbc205be4ef4be5da709d/jsonpointer-3.1.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9d/1b/2024d06792d0779f9dbc51531b61c24f76c75b9f4ce05e6f3377a1814cea/orjson-3.11.8.tar.gz"}}, {"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"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/55/f4/2a7c3c68e564a099becfa44bb3d398810cc0ff6749b0d3cb8ccb93f23c14/xxhash-3.6.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}]} +{"name": "launchdarkly-server-sdk", "version": "9.15.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/79/0e/fb5954448bcdef93475d14d2500edd9730c6d7dc02a3bb9732c602ac2981/launchdarkly_server_sdk-9.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/54/c6/c0816382050a97ebf0e4590e0adf93a317e7e64333eed4467b1081b261d7/launchdarkly_eventsource-1.5.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/cb/84/a04c59324445f4bcc98dc05b39a1cd07c242dde643c1a3c21e4f7beaf2f2/expiringdict-1.2.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/34/90/0200184d2124484f918054751ef997ed6409cb05b7e8dcbf5a22da4c4748/pyrfc3339-2.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl"}}]} +{"name": "litellm", "version": "1.83.4", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/b8/bd/df19d3f8f6654535ee343a341fd921f81c411abf601a53e3eaef58129b02/litellm-1.83.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/a6/aa109a33671f7a5d3bd78b46da9d852797c5e665bfda7d6b373f56bff2ec/aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/9e/5bfa2270f902d5b92ab7d41ce0475b8630572e71e349b2a4996d14bdda93/openai-2.30.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e6/d7/0110b8f54c008466b19672c615f2168896b83706a6611ba6e47313dbc6e9/tiktoken-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/8c/c7a33f3efaa8d6a5bc40e012e5ecc2d72c2e6124550ca9085fe0ceed9993/huggingface_hub-1.10.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b5/9c/defb6cb1de28bccb7bd8d95f6e60f72a3d3fa4cb3d0329c26fb9a488bfe7/hf_xet-1.4.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/05/57/7dbc0ffbbb5176a27e3518716608aa464aee2e2887dc938f0b900a120449/jiter-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/f1/dab7ac5e7306fb79c0190766a3c00b4cb8d09a1f390ded68c85a5934faf5/yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d5/1f/5f4a3cd9e4440e9d9bc78ad0a91a1c8d46b4d429d5239ebe6793c9fe5c41/fsspec-2026.3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/5b/f53b9ad17480b3ddd14c90da04bfb55ac6894b129e5dea87bcaf7d00e336/regex-2026.4.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d5/91/9b286ab899c008c2cb05e8be99814807e7fbbd33f0c0c960470826e5ac82/typer-0.23.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}]} +{"name": "openai", "version": "2.31.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/66/bc/a8f7c3aa03452fedbb9af8be83e959adba96a6b4a35e416faffcc959c568/openai-2.31.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/05/57/7dbc0ffbbb5176a27e3518716608aa464aee2e2887dc938f0b900a120449/jiter-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}]} +{"name": "openai-agents", "version": "0.13.6", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/1c/83/a991b2ad389abadabf13f6c4228bd88ac8dc363e4b50fcae8c5ea966bd41/openai_agents-0.13.6-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9c/46/f6b4ad632c67ef35209a66127e4bddc95759649dd595f71f13fba11bdf9a/mcp-1.27.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/66/bc/a8f7c3aa03452fedbb9af8be83e959adba96a6b4a35e416faffcc959c568/openai-2.31.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/05/57/7dbc0ffbbb5176a27e3518716608aa464aee2e2887dc938f0b900a120449/jiter-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/90/b8/78fd6c037de4788c040fdd323b3369804400351b7827473920f6c1d03c10/types_requests-2.33.0.20260408-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/22/f1925cdda983ab66fc8ec6ec8014b959262747e58bdca26a4e3d1da29d56/python_multipart-0.0.26-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f8/7f/3de5402f39890ac5660b86bcf5c03f9d855dad5c4ed764866d7b592b46fd/sse_starlette-3.3.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/c9/584bc9651441b4ba60cc4d557d8a547b5aff901af35bda3a4ee30c819b82/starlette-1.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/23/a5bbd9600dd607411fa644c06ff4951bec3a4d82c4b852374024359c19c0/uvicorn-0.44.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}]} +{"name": "openai-agents", "version": "0.8.4", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/55/dc/10df015aebb0797a8367aab65200ac4f5221df20bbae76930f5b6ac8e001/openai_agents-0.8.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9c/83/3b1d03d36f224edded98e9affd0467630fc09d766c0e56fb1498cbb04a9b/griffe-1.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9c/46/f6b4ad632c67ef35209a66127e4bddc95759649dd595f71f13fba11bdf9a/mcp-1.27.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/66/bc/a8f7c3aa03452fedbb9af8be83e959adba96a6b4a35e416faffcc959c568/openai-2.31.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/05/57/7dbc0ffbbb5176a27e3518716608aa464aee2e2887dc938f0b900a120449/jiter-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/90/b8/78fd6c037de4788c040fdd323b3369804400351b7827473920f6c1d03c10/types_requests-2.33.0.20260408-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/22/f1925cdda983ab66fc8ec6ec8014b959262747e58bdca26a4e3d1da29d56/python_multipart-0.0.26-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f8/7f/3de5402f39890ac5660b86bcf5c03f9d855dad5c4ed764866d7b592b46fd/sse_starlette-3.3.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/c9/584bc9651441b4ba60cc4d557d8a547b5aff901af35bda3a4ee30c819b82/starlette-1.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/23/a5bbd9600dd607411fa644c06ff4951bec3a4d82c4b852374024359c19c0/uvicorn-0.44.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}]} {"name": "openfeature-sdk", "version": "0.7.5", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/9b/20/cb043f54b11505d993e4dd84652cfc44c1260dc94b7f41aa35489af58277/openfeature_sdk-0.7.5-py3-none-any.whl"}}]} {"name": "openfeature-sdk", "version": "0.8.4", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/9c/80/f6532778188c573cc83790b11abccde717d4c1442514e722d6bb6140e55c/openfeature_sdk-0.8.4-py3-none-any.whl"}}]} -{"name": "pydantic-ai", "version": "1.70.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/fa/08/3a49448850ecdbc020ffa9fde9b7e4f6986c4d67488da33c17bc2150616c/pydantic_ai-1.70.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/8c/8545d28d0b3a9957aa21393cfdab8280bb854362360b296cd486ed1713ec/pydantic_ai_slim-1.70.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/13/9a/6d5b74b602820621bb225e47d47f514d72e5ac5119e5dd740cd493e8ffa7/pydantic_evals-1.70.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/fd/19c42b60c37dfdbbf5b76c7b218e8309b43dac501f7aaf2025527ca05023/pydantic_graph-1.70.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/21/db/7d5118d28b0918888e1ec98f56f659fdb006351e06d95f30f4274962a76f/temporalio-1.20.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/13/04/eaac430d0e6bf21265ae989427d37e94be5e41dc216879f1fbb6c5339942/nexus_rpc-1.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/6f/75/ca21955d6117a394a482c7862ce96216239d0e3a53133ae8510727a8bcfa/huggingface_hub-1.7.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/82/56/19c25105ff81731ca6d55a188b5de2aa99d7a2644c7aa9de1810d5d3b726/hf_xet-1.4.2-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fd/d9/eaa1f80170d2b7c5ba23f3b59f766f3a0bb41155fbc32a69adfa1adaaef9/mcp-1.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/99/eaa83816924791fc25ebb44ac7987196b687a3fdf597b1e7a62c69306a8d/ag_ui_protocol-0.1.14-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e1/5a/9d85b85686d5cdd79f5488c8667e668d7920d06a0a1a1beb454a5b77b2db/anthropic-0.85.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/62/92/1661d8b9fd6a3d7a2d89831db26fe3c1509a287d83ad7838831c7b7a5c7e/jiter-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/a1/128e3676fb9b4fd965a93554e5e07045975ee6bd6e9fdb536cdffa32e99e/boto3-1.42.70-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fb/51/08f32aea872253173f513ba68122f4300966290677c8e59887b4ffd5d957/botocore-1.42.70-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9d/86/dc991a75e3b9c2007b90dbfaf7f36fdb2457c216f799e26ce0474faf0c1f/cohere-5.20.7-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/65/8b/fa2d3287fd2267be6261d0177c6809a7fa12c5600ddb33490c8dc29e77b2/fastavro-1.12.1.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/31/93/8878be7569f87b14f1d52032946131bcb6ebbd8af3e20446bc04053dc3f1/charset_normalizer-3.4.6-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1c/12/709ea261f2bf91ef0a26a9eed20f2623227a8ed85610c1e54c5805692ecb/types_requests-2.32.4.20260107-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/70/ea/570122de7e24f72138d006f799768e14cc1ccf7fcb22b7750b2bd276c711/fastmcp-3.1.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/32/69/f1b537ee70b7def42d63124a539ed3026a11a3ffc3086947a1ca6e861868/py_key_value_aio-0.4.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/50/25/da1f0b4dd970e52bf5a36c204c107e11a0c6d3ed195eba0bfbc664c312b2/aiofile-3.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/86/93/1f76c8d1bafe3b0614e06b2195784a3765bbf7b0a067661af9e2dd47fc33/caio-0.9.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/53/23/b65f568ed0c22f1efacb744d2db1a33c8068f384b8c9b482b52ebdbc3ef6/authlib-1.6.9-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/06/f3/39cf3367b8107baa44f861dc802cbf16263c945b62d8265d36034fc07bea/cachetools-7.0.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/06/06/d68a5d5d292c2ad2bc6a02e5ca2cb1bb9c15e941ab02f004a06a342d7f0f/cyclopts-4.10.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/13/2f/b4530fbf948867702d0a3f27de4a6aab1d156f406d72852ab902c4d04de9/rich_rst-1.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c4/98/66a06b82a5c840f896490d5ef9c7691776b147589f2e8d2fa66c67a3db9c/genai_prices-0.0.55-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/eb/c6c2478d8a8d633460be40e2a8a6f8f429171997a35a96f81d3b680dec83/google_auth-2.49.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/84/de/7d3ee9c94b74c3578ea4f88d45e8de9405902f857932334d81e89bce3dfa/google_genai-1.68.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4d/51/c936033e16d12b627ea334aaaaf42229c37620d0f15593456ab69ab48161/griffelib-2.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/8f/1d/0749c5f0ed76693f6a3a40e2b0c40201fa23e1ccb00e69d5aa63e3f5b0ff/groq-1.1.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/d5/4e96c44f6c1ea3d812cf5391d81a4f5abaa540abf8d04ecd7f66e0ed11df/jsonschema_path-0.4.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/52/96/5a770e5c461462575474468e5af931cff9de036e7c2b4fea23c1c58d2cbe/pathable-0.5.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/aa/fb8102ea48924fbbb9dfced7bada5717875801808ad53f9a60b6b4fec440/logfire-4.29.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/95/f1/b27d3e2e003cd9a3592c43d099d2ed8d0a947c15281bf8463a256db0b46c/opentelemetry_exporter_otlp_proto_http-1.39.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/8c/02/ffc3e143d89a27ac21fd557365b98bd0653b98de8a101151d5805b5d4c33/opentelemetry_exporter_otlp_proto_common-1.39.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/51/95/b40c96a7b5203005a0b03d8ce8cd212ff23f1793d5ba289c87a097571b18/opentelemetry_proto-1.39.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/28/23eea8acd65972bbfe295ce3666b28ac510dfcb115fac089d3edb0feb00a/googleapis_common_protos-1.73.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/cc/62df4abc3e4650c25b81a8e39a1d498d3246c43f3aa4bfab7a73689317b4/logfire_api-4.29.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d1/17/40f62cf8be54ec857d95da7ea777b8a1bca289ca0d108bc8141e47dee3ac/mistralai-2.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/cf/22/fdc2e30d43ff853720042fa15baa3e6122722be1a7950a98233ebb55cd71/eval_type_backport-0.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d0/b1/35b6f9c8cf9318e3dbb7146cc82dab4cf61182a8d5406fc9b50864362895/openai-2.29.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/77/d2/6788e83c5c86a2690101681aeef27eeb2a6bf22df52d3f263a22cee20915/opentelemetry_instrumentation-0.60b1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d1/86/2fcad95994d9b572db57632acb6f900695a648c3e063f2cd344b3f5c5a37/wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/43/59/b98e84eebf745ffc75397eaad4763795bff8a30cbf2373a50ed4e70646c5/opentelemetry_instrumentation_httpx-0.60b1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/5c/d3f1733665f7cd582ef0842fb1d2ed0bc1fba10875160593342d22bba375/opentelemetry_util_http-0.60b1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/63/d7/97f7e3a6abb67d8080dd406fd4df842c2be0efaf712d1c899c32a075027c/platformdirs-4.9.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/e2/b8cff57a67dddf9a464d7e943218e031617fb3ddc133aeeb0602ff5f6c85/sse_starlette-3.3.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e6/d7/0110b8f54c008466b19672c615f2168896b83706a6611ba6e47313dbc6e9/tiktoken-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fb/69/4144b60ed7760a6bd235e4087041f487aa4aa62b45618ce018b0c14833ea/regex-2026.2.28-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2e/e8/1fd38926f9cf031188fbc5a96694203ea6f24b0e34bd64a225ec6f6291ba/types_protobuf-6.32.1.20260221-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ff/7f/4320d9ce3be404e6310b915c3629fe27bf1e2f438a1a7a3cb0396e32e9a9/uncalled_for-0.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0a/89/f8827ccff89c1586027a105e5630ff6139a64da2515e24dafe860bd9ae4d/uvicorn-0.42.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c0/ec/e47e307c2f4bd75f9f9e8afbe3876679b18e1bcec449beca132a1c5ffb2d/watchfiles-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4c/09/c85d9d8861ca3969f0456725436dcc48b1a9ae92735d0962f095966b1592/xai_sdk-1.8.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/90/03/c1d4ef9a054e151cd7839cdc497f2638f00b93cbe8043983986630d7a80c/aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/f1/dab7ac5e7306fb79c0190766a3c00b4cb8d09a1f390ded68c85a5934faf5/yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f4/49/c152890d49102b280ecf86ba5f80a8c111c3a155dafa3bd24aeb64fde9e1/jaraco_context-6.1.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fd/c4/813bb09f0985cb21e959f21f2464169eca882656849adf727ac7bb7e1767/jaraco_functools-4.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl"}}]} -{"name": "pyramid", "version": "2.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/50/bd/c336448be43d40be28e71f2e0f3caf7ccb28e2755c58f4c02c065bfe3e8e/WebOb-1.8.9-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/86/a4/77daa5ba398996d16bb43fc721599d27d03eae68fe3c799de1963c72e228/zope_interface-8.2.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}]} -{"name": "quart", "version": "0.20.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/7e/e9/cc28f21f52913adf333f653b9e0a3bf9cb223f5083a26422968ba73edd8d/quart-0.20.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ec/f9/7f9263c5695f4bd0023734af91bedb2ff8209e8de6ead162f35d8dc762fd/flask-3.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ad/e4/8d97cca767bcc1be76d16fb76951608305561c6e056811587f36cb1316a8/werkzeug-3.1.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}]} -{"name": "redis", "version": "7.3.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/f0/28/84e57fce7819e81ec5aa1bd31c42b89607241f4fb1a3ea5b0d2dbeaea26c/redis-7.3.0-py3-none-any.whl"}}]} -{"name": "requests", "version": "2.32.5", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl"}}]} -{"name": "rq", "version": "2.7.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/0d/1a/3b64696bc0c33aa1d86d3e6add03c4e0afe51110264fd41208bd95c2665c/rq-2.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/86/cf/f6180b67f99688d83e15c84c5beda831d1d341e95872d224f87ccafafe61/redis-7.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/07/4b/290b4c3efd6417a8b0c284896de19b1d5855e6dbdb97d2a35e68fa42de85/croniter-6.0.0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}]} -{"name": "sanic", "version": "25.12.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/9e/8a/16adaf66d358abfd0d24f2b76857196cf7effbf75c01306306bf39904e30/sanic-25.12.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e1/c6/76dc613121b793286a3f91621d7b75a2b493e0390ddca50f11993eadf192/setuptools-82.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1b/be/ae26a6321179ebbb3a2e2685b9007c71bcda41ad7a77bbbe164005e956fc/ujson-5.11.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}]} +{"name": "pydantic-ai", "version": "1.80.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/2c/9a/6d65ea560f8e84f57cf5cf7f5b611d48bd5d1869120bc7fcc3b40aed0556/pydantic_ai-1.80.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/23/bf/ef273265ef3530cf432fd6d0014ceed57d1cc5b1550fd975bc91152633c8/pydantic_ai_slim-1.80.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ee/28/8480d2e53728a891e1157f6c741a7f2ec27da06b56936d5c6e1f64af0e51/pydantic_evals-1.80.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/12/483b7402d302021ff8537a746eebf018f4e0bb5892c7bef769ab968e03c1/pydantic_graph-1.80.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/8c/c7a33f3efaa8d6a5bc40e012e5ecc2d72c2e6124550ca9085fe0ceed9993/huggingface_hub-1.10.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b5/9c/defb6cb1de28bccb7bd8d95f6e60f72a3d3fa4cb3d0329c26fb9a488bfe7/hf_xet-1.4.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9c/46/f6b4ad632c67ef35209a66127e4bddc95759649dd595f71f13fba11bdf9a/mcp-1.27.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/a0/a73398d30bb0f9ad70cd70426151a4a19527a7296e48a3a16a50e1d5db05/ag_ui_protocol-0.1.15-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/ac/7185750e8688f6ff79b0e3d6a61372c88b81ba81fcda8798c70598e18aca/anthropic-0.94.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/55/e2/2537ebcff11c1ee1ff17d8d0b6f4db75873e3b0fb32c2d4a2ee31ecb310a/docstring_parser-0.17.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/05/57/7dbc0ffbbb5176a27e3518716608aa464aee2e2887dc938f0b900a120449/jiter-0.14.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0a/2b/8bfddb39a19f5fbc16a869f1a394771e6223f07160dbc0ff6b38e05ea0ae/boto3-1.42.88-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/46/ad14e41245adb8b0c83663ba13e822b68a0df08999dd250e75b0750fdf6c/botocore-1.42.88-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9e/b4/00c2f9f8387a2e77faf8410210466c46d55dd30a0388de41c54441b148fb/cohere-6.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/65/8b/fa2d3287fd2267be6261d0177c6809a7fa12c5600ddb33490c8dc29e77b2/fastavro-1.12.1.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/90/b8/78fd6c037de4788c040fdd323b3369804400351b7827473920f6c1d03c10/types_requests-2.33.0.20260408-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f5/48/84b6dcba793178a44b9d99b4def6cd62f870dcfc5bb7b9153ac390135812/fastmcp-3.2.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/32/69/f1b537ee70b7def42d63124a539ed3026a11a3ffc3086947a1ca6e861868/py_key_value_aio-0.4.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/50/25/da1f0b4dd970e52bf5a36c204c107e11a0c6d3ed195eba0bfbc664c312b2/aiofile-3.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/86/93/1f76c8d1bafe3b0614e06b2195784a3765bbf7b0a067661af9e2dd47fc33/caio-0.9.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/53/23/b65f568ed0c22f1efacb744d2db1a33c8068f384b8c9b482b52ebdbc3ef6/authlib-1.6.9-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/71/cc/18245721fa7747065ab478316c7fea7c74777d07f37ae60db2e84f8172e8/beartype-0.22.9-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/06/f3/39cf3367b8107baa44f861dc802cbf16263c945b62d8265d36034fc07bea/cachetools-7.0.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b4/bd/05055d8360cef0757d79367157f3b15c0a0715e81e08f86a04018ec045f0/cyclopts-4.10.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/13/2f/b4530fbf948867702d0a3f27de4a6aab1d156f406d72852ab902c4d04de9/rich_rst-1.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d5/1f/5f4a3cd9e4440e9d9bc78ad0a91a1c8d46b4d429d5239ebe6793c9fe5c41/fsspec-2026.3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a3/f6/8ef7e4c286deb2709d11ca96a5237caae3ef4876ab3c48095856cfd2df30/genai_prices-0.0.56-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9f/3d/9f70246114cdf56a2615a40428ced08bc844f5a26247fe812b2f0dd4eaca/google_genai-1.72.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/34/b0/83e3892a4597a4b8ebf8a662aeaf314765c4c2340516eb1d049b459b24fc/groq-1.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/d5/4e96c44f6c1ea3d812cf5391d81a4f5abaa540abf8d04ecd7f66e0ed11df/jsonschema_path-0.4.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/52/96/5a770e5c461462575474468e5af931cff9de036e7c2b4fea23c1c58d2cbe/pathable-0.5.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/02/33/81b13e1f2044b5fe0112068a2494526db9cfdf784030a2ea57688279360a/logfire-4.32.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/95/f1/b27d3e2e003cd9a3592c43d099d2ed8d0a947c15281bf8463a256db0b46c/opentelemetry_exporter_otlp_proto_http-1.39.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/8c/02/ffc3e143d89a27ac21fd557365b98bd0653b98de8a101151d5805b5d4c33/opentelemetry_exporter_otlp_proto_common-1.39.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/51/95/b40c96a7b5203005a0b03d8ce8cd212ff23f1793d5ba289c87a097571b18/opentelemetry_proto-1.39.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b6/b0/be5d3329badb9230b765de6eea66b73abd5944bdeb5afb3562ddcd80ae84/googleapis_common_protos-1.74.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/58/56/fe8d8aa60e796e059992fb7359ec5dda4ef72db4fccfbd362a2ee0595ec1/logfire_api-4.32.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/e0/9f246d18f8fe6e815f7cae88c437c986b342d3ff568607c8e0d53f4710d0/mistralai-2.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/cf/22/fdc2e30d43ff853720042fa15baa3e6122722be1a7950a98233ebb55cd71/eval_type_backport-0.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/28/50/1a313fb700526b134c71eb8a225d8b83be0385dbb0204337b4379c698cef/jsonpath_python-1.1.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/66/bc/a8f7c3aa03452fedbb9af8be83e959adba96a6b4a35e416faffcc959c568/openai-2.31.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/12/cf/03675d8bd8ecbf4445504d8071adab19f5f993676795708e36402ab38263/openapi_pydantic-0.5.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/77/d2/6788e83c5c86a2690101681aeef27eeb2a6bf22df52d3f263a22cee20915/opentelemetry_instrumentation-0.60b1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d1/86/2fcad95994d9b572db57632acb6f900695a648c3e063f2cd344b3f5c5a37/wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/43/59/b98e84eebf745ffc75397eaad4763795bff8a30cbf2373a50ed4e70646c5/opentelemetry_instrumentation_httpx-0.60b1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/5c/d3f1733665f7cd582ef0842fb1d2ed0bc1fba10875160593342d22bba375/opentelemetry_util_http-0.60b1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/99/5f/86b1630be61bdebf253c2f953a6c3f073ec21bb0725565ea3896802e1ca3/pydantic_handlebars-0.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e5/7a/8dd906bd22e79e47397a61742927f6747fe93242ef86645ee9092e610244/pyjwt-2.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/df/80/fc9d01d5ed37ba4c42ca2b55b4339ae6e200b456be3a1aaddf4a9fa99b8c/pyperclip-1.11.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/22/f1925cdda983ab66fc8ec6ec8014b959262747e58bdca26a4e3d1da29d56/python_multipart-0.0.26-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/83/69/8bbc8b07ec854d92a8b75668c24d2abcb1719ebf890f5604c61c9369a16f/rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f8/7f/3de5402f39890ac5660b86bcf5c03f9d855dad5c4ed764866d7b592b46fd/sse_starlette-3.3.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0b/c9/584bc9651441b4ba60cc4d557d8a547b5aff901af35bda3a4ee30c819b82/starlette-1.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/de/9c/3782bab0bf11a40b550147c19a5d1a476c17405391751982408902d9f138/temporalio-1.25.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/11/52/6327a5f4fda01207205038a106a99848a41c83e933cd23ea2cab3d2ebc6c/nexus_rpc-1.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2e/e8/1fd38926f9cf031188fbc5a96694203ea6f24b0e34bd64a225ec6f6291ba/types_protobuf-6.32.1.20260221-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e6/d7/0110b8f54c008466b19672c615f2168896b83706a6611ba6e47313dbc6e9/tiktoken-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/5b/f53b9ad17480b3ddd14c90da04bfb55ac6894b129e5dea87bcaf7d00e336/regex-2026.4.4-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/11/e1/7ec67882ad8fc9f86384bef6421fa252c9cbe5744f8df6ce77afc9eca1f5/uncalled_for-0.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/23/a5bbd9600dd607411fa644c06ff4951bec3a4d82c4b852374024359c19c0/uvicorn-0.44.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c0/ec/e47e307c2f4bd75f9f9e8afbe3876679b18e1bcec449beca132a1c5ffb2d/watchfiles-1.1.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/76/86d9a3589c725ce825d2ed3e7cb3ecf7f956d3fd015353d52197bb341bcd/xai_sdk-1.11.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bb/a6/aa109a33671f7a5d3bd78b46da9d852797c5e665bfda7d6b373f56bff2ec/aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/48/af6173dbca4454f4637a4678b67f52ca7e0c1ed7d5894d89d434fecede05/grpcio-1.80.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/f1/dab7ac5e7306fb79c0190766a3c00b4cb8d09a1f390ded68c85a5934faf5/yarl-1.23.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/01/20/b0972d902472da9bcb683fa595099911f4d2e86e5683bcc45de60dd05dc3/propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fd/c4/813bb09f0985cb21e959f21f2464169eca882656849adf727ac7bb7e1767/jaraco_functools-4.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/cb/98/6af411189d9413534c3eb691182bff1f5c6d44ed2f93f2edfe52a1bbceb8/more_itertools-11.0.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl"}}]} +{"name": "pyramid", "version": "2.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/1f/d4/03a8f9b60b8f2a9198c962d08fd9b657c1c0797cbbde3793babbad200845/pyramid-2.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e1/e3/c164c88b2e5ce7b24d667b9bd83589cf4f3520d97cad01534cd3c4f55fdb/setuptools-81.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/86/7d/3888833e4f5ea56af4a9935066ec09a83228e533d7b8877f65889d706ee4/hupper-1.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3b/98/36187601a15e3d37e9bfcf0e0e1055532b39d044353b06861c3a519737a9/translationstring-1.4-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5a/4b/34d926eba40db81b204066a60b4efdc5d8867a8efcbfe44d69b634b1c907/venusian-3.1.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/50/bd/c336448be43d40be28e71f2e0f3caf7ccb28e2755c58f4c02c065bfe3e8e/WebOb-1.8.9-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/8c/7e/e7394eeb49a41cc514b3eb49020223666cbf40d86f5721c2f07871e6d84a/legacy_cgi-2.6.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e9/ed/da7f8b1c73caf989a0ff7096cc73c59e6c36f35a8f967c51104098602e2d/zope_deprecation-6.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c9/04/0b1d92e7d31507c5fbe203d9cc1ae80fb0645688c7af751ea0ec18c2223e/zope_interface-8.3.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e7/8b/3f98db1448e3b4d2d142716874a7e02f6101685fdaa0f55a8668e9ffa048/plaster-1.1.2-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bd/30/2d4cf89035c22a89bf0e34dbc50fdc07c42c9bdc90fd972d495257ad2b6e/plaster_pastedeploy-1.0.1-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/85/30/cdddd9a88969683a59222a6d61cd6dce923977f2e9f9ffba38e1324149cd/PasteDeploy-3.1.0-py3-none-any.whl"}}]} +{"name": "quart", "version": "0.20.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/7e/e9/cc28f21f52913adf333f653b9e0a3bf9cb223f5083a26422968ba73edd8d/quart-0.20.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/7f/9c/34f6962f9b9e9c71f6e5ed806e0d0ff03c9d1b0b2340088a0cf4bce09b18/flask-3.1.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/93/35/850277d1b17b206bd10874c8a9a3f52e059452fb49bb0d22cbb908f6038b/hypercorn-0.18.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/93/8c/2e650f2afeb7ee576912636c23ddb621c91ac6a98e66dc8d29c3c69446e1/werkzeug-3.1.8-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/5e/5f/82c8074f7e84978129347c2c6ec8b6c59f3584ff1a20bc3c940a3e061790/priority-2.0.0-py3-none-any.whl"}}]} +{"name": "redis", "version": "7.4.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/74/3a/95deec7db1eb53979973ebd156f3369a72732208d1391cd2e5d127062a32/redis-7.4.0-py3-none-any.whl"}}]} +{"name": "redis", "version": "8.0.0b1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/aa/d8/78afb14bfac6cabae6fffce26263eec80bef0943c7d1e3ef4c50a80a67b8/redis-8.0.0b1-py3-none-any.whl"}}]} +{"name": "requests", "version": "2.33.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}]} +{"name": "rq", "version": "2.7.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/0d/1a/3b64696bc0c33aa1d86d3e6add03c4e0afe51110264fd41208bd95c2665c/rq-2.7.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/74/3a/95deec7db1eb53979973ebd156f3369a72732208d1391cd2e5d127062a32/redis-7.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d0/39/783980e78cb92c2d7bdb1fc7dbc86e94ccc6d58224d76a7f1f51b6c51e30/croniter-6.2.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}]} +{"name": "sanic", "version": "25.12.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/9e/8a/16adaf66d358abfd0d24f2b76857196cf7effbf75c01306306bf39904e30/sanic-25.12.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9b/12/2f5d43ee912ea14a6baba4b3db6d309b02d932e3b7074c3339b4aded98ff/html5tagger-1.3.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/cf/e3/3425c9a8773807ac2c01d6a56c8521733f09b627e5827e733c5cd36b9ac5/sanic_routing-23.12.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b6/62/3f385a67ff3cc91209f107d20bbebdecf7a4e4aba55a43f9f71bddc424a9/tracerite-2.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/24/c2/8abffa3be1f3d605c4a62445fab232b3e7681512ce941c6b23014f404d36/ujson-5.12.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl"}}]} {"name": "sqlalchemy", "version": "2.1.0b1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/45/eb/07e192fa2e1deb500e86e0b86883037116447360951a6c3eda2ce4f176f7/sqlalchemy-2.1.0b1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}]} -{"name": "starlette", "version": "0.52.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}]} -{"name": "starlette", "version": "1.0.0rc1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/37/63/843f3f4aa2cbdadb6becddceb81d034cc417fbecd2fb0e105092a8c82a8a/starlette-1.0.0rc1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}]} -{"name": "statsig", "version": "0.55.3", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/9d/17/de62fdea8aab8aa7c4a833378e0e39054b728dfd45ef279e975ed5ef4e86/statsig-0.55.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/2a/97/e88295f9456ba939d90d4603af28fcabda3b443ef55e709e9381df3daa58/ijson-3.4.0.post0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/37/be6dfbfa45719aa82c008fb4772cfe5c46db765a2ca4b6f524a1fdfee4d7/ua_parser-1.0.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/10/4a/ce8a586f7376f6bceabfe5f12f5e542db998517f08a461bb18294ff19bd1/ua_parser_builtins-202602-py3-none-any.whl"}}]} -{"name": "statsig", "version": "0.71.6", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b1/aba1475b024e99883b5b43405e5713520129ce42004bc39a3fb40312724b/statsig-0.71.6-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/06/8a/3d098f35c143a89520e568e6539cc098fcd294495910e359889ce8741c84/grpcio-1.78.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/38/14/52b6613fdda4078c62eb5b4fe3efc724ddc55a4ad524c93de51830107aa3/ijson-3.5.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a4/e7/14dc9366696dcb53a413449881743426ed289d687bcf3d5aee4726c32ebb/protobuf-7.34.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/fc/97/440635fc093b8d7347502a377031f9605a1039c958f3cd18dcacffb37743/charset_normalizer-3.4.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/37/be6dfbfa45719aa82c008fb4772cfe5c46db765a2ca4b6f524a1fdfee4d7/ua_parser-1.0.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3e/6f/73a4d37deefb159556d39d654b5bad67b6874d1ad0b20b96fb5a04de3949/ua_parser_builtins-202603-py3-none-any.whl"}}]} -{"name": "strawberry-graphql", "version": "0.311.3", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/6b/7b/4ffdda96126397b31318ae429b9db5790f47c7f17568f98ca61778929494/strawberry_graphql-0.311.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/86/41/cb887d9afc5dabd78feefe6ccbaf83ff423c206a7a1b7aeeac05120b2125/graphql_core-3.2.8-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/67/49/92b46b6e65f09b717a66c4e5a9bc47a45ebc83dd0e0ed126f8258363479d/cross_web-0.4.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}]} -{"name": "typer", "version": "0.24.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}]} +{"name": "starlette", "version": "0.52.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}]} +{"name": "starlette", "version": "1.0.0", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/0b/c9/584bc9651441b4ba60cc4d557d8a547b5aff901af35bda3a4ee30c819b82/starlette-1.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}]} +{"name": "statsig", "version": "0.55.3", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/9d/17/de62fdea8aab8aa7c4a833378e0e39054b728dfd45ef279e975ed5ef4e86/statsig-0.55.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/48/af6173dbca4454f4637a4678b67f52ca7e0c1ed7d5894d89d434fecede05/grpcio-1.80.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/35/8b/3e703e8cc4b3ada79f13b28070b51d9550c578f76d1968657905857b2ddd/ijson-3.5.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/88/95/608f665226bca68b736b79e457fded9a2a38c4f4379a4a7614303d9db3bc/protobuf-7.34.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3e/6f/73a4d37deefb159556d39d654b5bad67b6874d1ad0b20b96fb5a04de3949/ua_parser_builtins-202603-py3-none-any.whl"}}]} +{"name": "statsig", "version": "0.71.6", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b1/aba1475b024e99883b5b43405e5713520129ce42004bc39a3fb40312724b/statsig-0.71.6-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/48/af6173dbca4454f4637a4678b67f52ca7e0c1ed7d5894d89d434fecede05/grpcio-1.80.0.tar.gz"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/35/8b/3e703e8cc4b3ada79f13b28070b51d9550c578f76d1968657905857b2ddd/ijson-3.5.0-cp314-cp314t-macosx_11_0_arm64.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d6/b7/48a7f1ab9eee62f1113114207df7e7e6bc29227389d554f42cc11bc98108/ip3country-0.4.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/88/95/608f665226bca68b736b79e457fded9a2a38c4f4379a4a7614303d9db3bc/protobuf-7.34.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/a9/7c/6367995ff57aaa2d9e1055adbaec2519cf5a979780a83a93fdf8c6ec37be/ua_parser-1.0.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/3e/6f/73a4d37deefb159556d39d654b5bad67b6874d1ad0b20b96fb5a04de3949/ua_parser_builtins-202603-py3-none-any.whl"}}]} +{"name": "strawberry-graphql", "version": "0.314.3", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/be/25/13773a2944cc5975d44db58233b3610ddc88d4be49e6576adf7ed4b62250/strawberry_graphql-0.314.3-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/86/41/cb887d9afc5dabd78feefe6ccbaf83ff423c206a7a1b7aeeac05120b2125/graphql_core-3.2.8-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/67/49/92b46b6e65f09b717a66c4e5a9bc47a45ebc83dd0e0ed126f8258363479d/cross_web-0.4.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl"}}]} +{"name": "typer", "version": "0.24.1", "dependencies": [{"download_info": {"url": "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e4/20/71885d8b97d4f3dde17b1fdb92dbd4908b00541c5a3379787137285f602e/click-8.3.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"}}, {"download_info": {"url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl"}}]} diff --git a/scripts/populate_tox/releases.jsonl b/scripts/populate_tox/releases.jsonl index 751c1eb87c..286f31b9b8 100644 --- a/scripts/populate_tox/releases.jsonl +++ b/scripts/populate_tox/releases.jsonl @@ -5,9 +5,9 @@ {"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.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.1.14", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "Django-3.1.14-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "Django-3.1.14.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.29", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "django-4.2.29-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "django-4.2.29.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.12", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "django-5.2.12-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "django-5.2.12.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.0.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "django-6.0.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "django-6.0.3.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.13", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "django-5.2.13-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "django-5.2.13.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.0.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "django-6.0.4-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "django-6.0.4.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", "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", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", "Topic :: Software Development :: Libraries :: Application Frameworks", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "Flask", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", "version": "1.1.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "Flask-1.1.4-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "Flask-1.1.4.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"}]} @@ -15,18 +15,18 @@ {"info": {"classifiers": ["Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: Flask", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "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.9", "version": "0.20.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "quart-0.20.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "quart-0.20.0.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 :: 3", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Database :: Front-Ends"], "name": "SQLAlchemy", "requires_python": "", "version": "1.2.19", "yanked": false}, "urls": [{"packagetype": "sdist", "filename": "SQLAlchemy-1.2.19.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.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.48", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp313-cp313t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp313-cp313t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp313-cp313t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp313-cp313t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp314-cp314t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp314-cp314t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp314-cp314t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp314-cp314t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp38-cp38-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp38-cp38-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp38-cp38-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-cp39-cp39-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.48-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "sqlalchemy-2.0.48.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.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.49", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp313-cp313t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp313-cp313t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp314-cp314t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp314-cp314t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp38-cp38-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp38-cp38-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp38-cp38-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-cp39-cp39-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.0.49-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "sqlalchemy-2.0.49.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 :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Database :: Front-Ends"], "name": "SQLAlchemy", "requires_python": ">=3.10", "version": "2.1.0b1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp310-cp310-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp311-cp311-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp312-cp312-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp313-cp313-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-cp314-cp314-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "sqlalchemy-2.1.0b1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "sqlalchemy-2.1.0b1.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.7.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "unleashclient-6.7.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "unleashclient-6.7.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.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP"], "name": "aiohttp", "requires_python": ">=3.8", "version": "3.10.11", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.10.11-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "aiohttp-3.10.11.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", "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", "Topic :: Internet :: WWW/HTTP"], "name": "aiohttp", "requires_python": ">=3.9", "version": "3.13.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.3-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "aiohttp-3.13.3.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", "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", "Topic :: Internet :: WWW/HTTP"], "name": "aiohttp", "requires_python": ">=3.9", "version": "3.13.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_riscv64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.13.5-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "aiohttp-3.13.5.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.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Internet :: WWW/HTTP"], "name": "aiohttp", "requires_python": ">=3.5.3", "version": "3.4.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp35-cp35m-macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp35-cp35m-macosx_10_11_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp35-cp35m-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp35-cp35m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp35-cp35m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp35-cp35m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp35-cp35m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp36-cp36m-macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp36-cp36m-macosx_10_11_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp36-cp36m-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp37-cp37m-macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp37-cp37m-macosx_10_11_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp37-cp37m-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "aiohttp-3.4.4-cp37-cp37m-win_amd64.whl"}, {"packagetype": "sdist", "filename": "aiohttp-3.4.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.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": ["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.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "anthropic", "requires_python": ">=3.8", "version": "0.39.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "anthropic-0.39.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "anthropic-0.39.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.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "anthropic", "requires_python": ">=3.8", "version": "0.62.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "anthropic-0.62.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "anthropic-0.62.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", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "anthropic", "requires_python": ">=3.9", "version": "0.86.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "anthropic-0.86.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "anthropic-0.86.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.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "anthropic", "requires_python": ">=3.8", "version": "0.42.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "anthropic-0.42.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "anthropic-0.42.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.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "anthropic", "requires_python": ">=3.8", "version": "0.68.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "anthropic-0.68.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "anthropic-0.68.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.94.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "anthropic-0.94.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "anthropic-0.94.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"}]} @@ -34,10 +34,10 @@ {"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.19.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.19.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.19.0-cp27-cp27m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.19.0-cp27-cp27m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.19.0-cp27-cp27mu-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.19.0-cp27-cp27mu-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.19.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.19.0-cp35-cp35m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.19.0-cp35-cp35m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.19.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.19.0-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.19.0-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.19.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.19.0-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.19.0-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "sdist", "filename": "apache-beam-2.19.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.27.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp36-cp36m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp36-cp36m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp36-cp36m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp36-cp36m-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp36-cp36m-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp37-cp37m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp37-cp37m-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp37-cp37m-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp38-cp38-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp38-cp38-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp38-cp38-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp38-cp38-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp38-cp38-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.27.0-cp38-cp38-win_amd64.whl"}, {"packagetype": "sdist", "filename": "apache-beam-2.27.0.zip"}]} {"info": {"classifiers": ["Intended Audience :: End Users/Desktop", "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", "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.42.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp37-cp37m-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp37-cp37m-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp37-cp37m-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp37-cp37m-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp37-cp37m-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp37-cp37m-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp38-cp38-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp38-cp38-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp38-cp38-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp38-cp38-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp38-cp38-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp38-cp38-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp39-cp39-manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp39-cp39-manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp39-cp39-manylinux2010_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp39-cp39-manylinux2010_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp39-cp39-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.42.0-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "apache-beam-2.42.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", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "apache-beam", "requires_python": ">=3.10", "version": "2.71.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.71.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "sdist", "filename": "apache_beam-2.71.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", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "apache-beam", "requires_python": ">=3.10", "version": "2.72.0rc2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0rc2-cp313-cp313-win_amd64.whl"}, {"packagetype": "sdist", "filename": "apache_beam-2.72.0rc2.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", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "apache-beam", "requires_python": ">=3.10", "version": "2.72.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "apache_beam-2.72.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "sdist", "filename": "apache_beam-2.72.0.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.0.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ariadne-1.0.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "ariadne-1.0.0.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.0.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ariadne-1.0.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "ariadne-1.0.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.0a2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ariadne-1.1.0a2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "ariadne-1.1.0a2.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.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.27.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "arq-0.27.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "arq-0.27.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"}]} @@ -47,19 +47,18 @@ {"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.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"], "name": "boto3", "requires_python": "", "version": "1.12.49", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "boto3-1.12.49-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "boto3-1.12.49.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.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "boto3", "requires_python": ">= 3.6", "version": "1.21.46", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "boto3-1.21.46-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "boto3-1.21.46.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.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "boto3", "requires_python": ">= 3.7", "version": "1.33.13", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "boto3-1.33.13-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "boto3-1.33.13.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 :: 3.9"], "name": "boto3", "requires_python": ">=3.9", "version": "1.42.71", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "boto3-1.42.71-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "boto3-1.42.71.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 :: 3.9"], "name": "boto3", "requires_python": ">=3.9", "version": "1.42.88", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "boto3-1.42.88-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "boto3-1.42.88.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 :: 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", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Object Brokering", "Topic :: System :: Distributed Computing"], "name": "celery", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", "version": "4.4.7", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "celery-4.4.7-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "celery-4.4.7.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.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "celery-5.6.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "celery-5.6.2.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", "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.16.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "chalice-1.16.0-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "chalice-1.16.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 :: 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": "chalice", "requires_python": null, "version": "1.32.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "chalice-1.32.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "chalice-1.32.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.10", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp310-cp310-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp310-cp310-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp311-cp311-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp311-cp311-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp312-cp312-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp312-cp312-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp312-cp312-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp313-cp313-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp313-cp313-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp313-cp313-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp314-cp314-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp314-cp314-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp314-cp314-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp38-cp38-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp38-cp38-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp38-cp38-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp38-cp38-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp38-cp38-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp38-cp38-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp39-cp39-musllinux_1_2_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp39-cp39-musllinux_1_2_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-cp39-cp39-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-pp310-pypy310_pp73-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-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.10-pp310-pypy310_pp73-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-pp311-pypy311_pp73-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-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.10-pp311-pypy311_pp73-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-pp39-pypy39_pp73-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-pp39-pypy39_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "clickhouse_driver-0.2.10-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.10-pp39-pypy39_pp73-win_amd64.whl"}, {"packagetype": "sdist", "filename": "clickhouse_driver-0.2.10.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", "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 :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "cohere", "requires_python": "<4.0,>=3.8", "version": "5.10.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "cohere-5.10.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "cohere-5.10.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.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "cohere", "requires_python": "<4.0,>=3.9", "version": "5.15.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "cohere-5.15.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "cohere-5.15.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", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "cohere", "requires_python": "<4.0,>=3.9", "version": "5.20.7", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "cohere-5.20.7-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "cohere-5.20.7.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": ["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.1.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "dramatiq-2.1.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "dramatiq-2.1.0.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 :: Python", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "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 :: Jython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Internet :: WWW/HTTP :: WSGI", "Topic :: Software Development :: Libraries :: Application Frameworks"], "name": "falcon", "requires_python": "", "version": "1.4.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "falcon-1.4.1-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "falcon-1.4.1.tar.gz"}]} @@ -67,29 +66,29 @@ {"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", "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.13", "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Free Threading", "Programming Language :: Python :: Free Threading :: 2 - Beta", "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.2.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "falcon-4.2.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "falcon-4.2.0.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", "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.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.117.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastapi-0.117.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastapi-0.117.1.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.135.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastapi-0.135.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastapi-0.135.1.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.135.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastapi-0.135.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastapi-0.135.3.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.6", "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.6.1", "version": "0.79.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastapi-0.79.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastapi-0.79.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.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.98.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastapi-0.98.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastapi-0.98.0.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "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.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Scientific/Engineering :: Information Analysis", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "fastavro", "requires_python": ">=3.9", "version": "1.12.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp310-cp310-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp312-cp312-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp313-cp313-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp313-cp313t-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp313-cp313t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp313-cp313t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp314-cp314-macosx_10_15_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp314-cp314t-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp314-cp314t-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp39-cp39-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastavro-1.12.1-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "fastavro-1.12.1.tar.gz"}]} {"info": {"classifiers": [], "name": "fastmcp", "requires_python": ">=3.10", "version": "0.1.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastmcp-0.1.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastmcp-0.1.0.tar.gz"}]} {"info": {"classifiers": [], "name": "fastmcp", "requires_python": ">=3.10", "version": "0.4.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastmcp-0.4.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastmcp-0.4.1.tar.gz"}]} {"info": {"classifiers": [], "name": "fastmcp", "requires_python": ">=3.10", "version": "1.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastmcp-1.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastmcp-1.0.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": "2.14.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastmcp-2.14.5-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastmcp-2.14.5.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": "3.1.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastmcp-3.1.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastmcp-3.1.1.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": "2.14.7", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastmcp-2.14.7-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastmcp-2.14.7.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": "3.2.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastmcp-3.2.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "fastmcp-3.2.3.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "License :: OSI Approved :: BSD License", "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", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Rust", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "fastuuid", "requires_python": ">=3.8", "version": "0.14.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp311-cp311-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp311-cp311-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp311-cp311-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp311-cp311-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp312-cp312-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp312-cp312-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp312-cp312-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp312-cp312-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp313-cp313-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp313-cp313-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp313-cp313-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp313-cp313-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp314-cp314-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp314-cp314-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp314-cp314-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp314-cp314-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp38-cp38-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp38-cp38-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp38-cp38-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp38-cp38-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp38-cp38-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp38-cp38-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp39-cp39-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp39-cp39-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp39-cp39-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp39-cp39-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "fastuuid-0.14.0-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "fastuuid-0.14.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", "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.42.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "google_genai-1.42.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "google_genai-1.42.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.55.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "google_genai-1.55.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "google_genai-1.55.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.68.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "google_genai-1.68.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "google_genai-1.68.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.43.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "google_genai-1.43.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "google_genai-1.43.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.57.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "google_genai-1.57.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "google_genai-1.57.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.72.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "google_genai-1.72.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "google_genai-1.72.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 :: 3.9", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries"], "name": "gql", "requires_python": ">=3.8.1", "version": "4.3.0b0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "gql-4.3.0b0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "gql-4.3.0b0.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 :: 3.9", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries"], "name": "gql", "requires_python": ">=3.8.1", "version": "4.3.0b2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "gql-4.3.0b2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "gql-4.3.0b2.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.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "grpcio", "requires_python": ">=3.6", "version": "1.47.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp310-cp310-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp310-cp310-macosx_12_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp310-cp310-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp310-cp310-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp310-cp310-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp36-cp36m-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp36-cp36m-macosx_10_10_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp36-cp36m-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp36-cp36m-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp36-cp36m-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp37-cp37m-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp37-cp37m-macosx_10_10_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp37-cp37m-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp37-cp37m-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp37-cp37m-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp38-cp38-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp38-cp38-macosx_10_10_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp38-cp38-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp38-cp38-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp38-cp38-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp39-cp39-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp39-cp39-macosx_10_10_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp39-cp39-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp39-cp39-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp39-cp39-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.47.5-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "grpcio-1.47.5.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.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "grpcio", "requires_python": ">=3.7", "version": "1.62.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp310-cp310-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp310-cp310-macosx_12_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp310-cp310-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp310-cp310-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp310-cp310-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp311-cp311-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp311-cp311-macosx_10_10_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp311-cp311-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp311-cp311-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp311-cp311-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp312-cp312-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp312-cp312-macosx_10_10_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp312-cp312-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp312-cp312-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp312-cp312-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp37-cp37m-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp37-cp37m-macosx_10_10_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp37-cp37m-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp37-cp37m-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp37-cp37m-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp38-cp38-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp38-cp38-macosx_10_10_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp38-cp38-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp38-cp38-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp38-cp38-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp39-cp39-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp39-cp39-macosx_10_10_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp39-cp39-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp39-cp39-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp39-cp39-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.62.3-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "grpcio-1.62.3.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.9"], "name": "grpcio", "requires_python": ">=3.9", "version": "1.78.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp310-cp310-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp310-cp310-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp310-cp310-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp311-cp311-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp311-cp311-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp311-cp311-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp312-cp312-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp312-cp312-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp312-cp312-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp313-cp313-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp313-cp313-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp313-cp313-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp314-cp314-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp314-cp314-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp314-cp314-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp39-cp39-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp39-cp39-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp39-cp39-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.78.0-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "grpcio-1.78.0.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.9"], "name": "grpcio", "requires_python": ">=3.9", "version": "1.80.0rc1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp310-cp310-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp310-cp310-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp310-cp310-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp311-cp311-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp311-cp311-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp311-cp311-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp312-cp312-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp312-cp312-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp312-cp312-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp313-cp313-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp313-cp313-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp313-cp313-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp314-cp314-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp314-cp314-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp314-cp314-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp39-cp39-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp39-cp39-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp39-cp39-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0rc1-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "grpcio-1.80.0rc1.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.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "grpcio", "requires_python": ">=3.6", "version": "1.48.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp310-cp310-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp310-cp310-macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp310-cp310-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp310-cp310-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp310-cp310-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp36-cp36m-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp36-cp36m-macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp36-cp36m-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp36-cp36m-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp36-cp36m-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp36-cp36m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp36-cp36m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp37-cp37m-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp37-cp37m-macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp37-cp37m-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp37-cp37m-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp37-cp37m-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp37-cp37m-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp37-cp37m-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp38-cp38-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp38-cp38-macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp38-cp38-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp38-cp38-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp38-cp38-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp39-cp39-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp39-cp39-macosx_10_10_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp39-cp39-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp39-cp39-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp39-cp39-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.48.2-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "grpcio-1.48.2.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.8", "Programming Language :: Python :: 3.9"], "name": "grpcio", "requires_python": ">=3.8", "version": "1.64.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp310-cp310-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp310-cp310-macosx_12_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp310-cp310-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp310-cp310-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp310-cp310-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp311-cp311-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp311-cp311-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp311-cp311-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp311-cp311-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp312-cp312-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp312-cp312-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp312-cp312-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp312-cp312-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp312-cp312-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp38-cp38-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp38-cp38-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp38-cp38-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp38-cp38-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp38-cp38-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp38-cp38-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp38-cp38-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp39-cp39-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp39-cp39-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp39-cp39-manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp39-cp39-musllinux_1_1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp39-cp39-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.64.3-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "grpcio-1.64.3.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.9"], "name": "grpcio", "requires_python": ">=3.9", "version": "1.80.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp310-cp310-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp310-cp310-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp310-cp310-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp311-cp311-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp311-cp311-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp311-cp311-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp312-cp312-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp312-cp312-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp312-cp312-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp313-cp313-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp313-cp313-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp313-cp313-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp314-cp314-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp314-cp314-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp314-cp314-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp314-cp314-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp39-cp39-linux_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp39-cp39-macosx_11_0_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp39-cp39-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "grpcio-1.80.0-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "grpcio-1.80.0.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", "Operating System :: MacOS :: MacOS X", "Operating System :: POSIX", "Programming Language :: Python :: 3"], "name": "httptools", "requires_python": ">=3.9", "version": "0.7.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp311-cp311-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp311-cp311-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp311-cp311-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp312-cp312-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp312-cp312-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp312-cp312-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp313-cp313-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp313-cp313-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp313-cp313-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp314-cp314-macosx_10_13_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp314-cp314-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp314-cp314-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp39-cp39-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp39-cp39-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp39-cp39-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "httptools-0.7.1-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "httptools-0.7.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.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"}]} @@ -105,19 +104,20 @@ {"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": ["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", "Programming Language :: Python :: 3.9", "Topic :: Scientific/Engineering :: Artificial Intelligence"], "name": "huggingface-hub", "requires_python": ">=3.9.0", "version": "1.7.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "huggingface_hub-1.7.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "huggingface_hub-1.7.1.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.10.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "huggingface_hub-1.10.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "huggingface_hub-1.10.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.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.28", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langchain-0.3.28-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langchain-0.3.28.tar.gz"}]} {"info": {"classifiers": [], "name": "langchain", "requires_python": "<4.0.0,>=3.10.0", "version": "1.0.8", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langchain-1.0.8-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langchain-1.0.8.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.2.12", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langchain-1.2.12-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langchain-1.2.12.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.2.15", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langchain-1.2.15-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langchain-1.2.15.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.1.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langgraph-1.1.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langgraph-1.1.3.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.1.6", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langgraph-1.1.6-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langgraph-1.1.6.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.1.7a1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "langgraph-1.1.7a1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "langgraph-1.1.7a1.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.15.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "launchdarkly_server_sdk-9.15.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "launchdarkly_server_sdk-9.15.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": ["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.79.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litellm-1.79.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "litellm-1.79.3.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": "<4.0,>=3.9", "version": "1.81.16", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litellm-1.81.16-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "litellm-1.81.16.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": "<4.0,>=3.9", "version": "1.82.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litellm-1.82.4-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "litellm-1.82.4.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.14", "Programming Language :: Python :: 3.9"], "name": "litellm", "requires_python": "<4.0,>=3.9", "version": "1.83.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litellm-1.83.4-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "litellm-1.83.4.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.14.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litestar-2.14.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "litestar-2.14.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.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.21.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "litestar-2.21.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "litestar-2.21.1.tar.gz"}]} @@ -126,18 +126,18 @@ {"info": {"classifiers": ["Development Status :: 4 - Beta", "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"], "name": "mcp", "requires_python": ">=3.10", "version": "1.15.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "mcp-1.15.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "mcp-1.15.0.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 4 - Beta", "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"], "name": "mcp", "requires_python": ">=3.10", "version": "1.19.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "mcp-1.19.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "mcp-1.19.0.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 4 - Beta", "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"], "name": "mcp", "requires_python": ">=3.10", "version": "1.23.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "mcp-1.23.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "mcp-1.23.3.tar.gz"}]} -{"info": {"classifiers": ["Development Status :: 4 - Beta", "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"], "name": "mcp", "requires_python": ">=3.10", "version": "1.26.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "mcp-1.26.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "mcp-1.26.0.tar.gz"}]} +{"info": {"classifiers": ["Development Status :: 4 - Beta", "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"], "name": "mcp", "requires_python": ">=3.10", "version": "1.27.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "mcp-1.27.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "mcp-1.27.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.105.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-1.105.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-1.105.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.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.8", "version": "1.106.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-1.106.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-1.106.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.70.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-1.70.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-1.70.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.13.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-2.13.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-2.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", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.9", "version": "2.22.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-2.22.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-2.22.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.26.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-2.26.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-2.26.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.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.8", "version": "1.71.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-1.71.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-1.71.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.15.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-2.15.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-2.15.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.24.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-2.24.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-2.24.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", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai", "requires_python": ">=3.9", "version": "2.29.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-2.29.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-2.29.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.30.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-2.30.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-2.30.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.31.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai-2.31.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai-2.31.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.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai-agents", "requires_python": ">=3.9", "version": "0.0.19", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai_agents-0.0.19-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai_agents-0.0.19.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.12.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai_agents-0.12.5-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai_agents-0.12.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.13.6", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai_agents-0.13.6-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai_agents-0.13.6.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.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai-agents", "requires_python": ">=3.9", "version": "0.4.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai_agents-0.4.2-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai_agents-0.4.2.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", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed"], "name": "openai-agents", "requires_python": ">=3.9", "version": "0.8.4", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "openai_agents-0.8.4-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "openai_agents-0.8.4.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"}]} @@ -145,9 +145,9 @@ {"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.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9"], "name": "pure-eval", "requires_python": null, "version": "0.2.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pure_eval-0.2.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pure_eval-0.2.3.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", "Topic :: Internet", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "pydantic-ai", "requires_python": ">=3.10", "version": "1.0.18", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pydantic_ai-1.0.18-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pydantic_ai-1.0.18.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", "Topic :: Internet", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "pydantic-ai", "requires_python": ">=3.10", "version": "1.23.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pydantic_ai-1.23.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pydantic_ai-1.23.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", "Topic :: Internet", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "pydantic-ai", "requires_python": ">=3.10", "version": "1.47.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pydantic_ai-1.47.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pydantic_ai-1.47.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": "1.70.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pydantic_ai-1.70.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pydantic_ai-1.70.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", "Topic :: Internet", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "pydantic-ai", "requires_python": ">=3.10", "version": "1.26.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pydantic_ai-1.26.0-py3-none-any.whl"}]} +{"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", "Topic :: Internet", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "pydantic-ai", "requires_python": ">=3.10", "version": "1.53.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pydantic_ai-1.53.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pydantic_ai-1.53.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": "1.80.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pydantic_ai-1.80.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pydantic_ai-1.80.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.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 :: 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", "Topic :: Database", "Typing :: Typed"], "name": "pymongo", "requires_python": ">=3.9", "version": "4.11.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp310-cp310-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp311-cp311-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp312-cp312-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp312-cp312-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313t-macosx_10_13_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313t-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313t-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313t-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp39-cp39-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp39-cp39-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "pymongo-4.11.3-cp39-cp39-win_amd64.whl"}, {"packagetype": "sdist", "filename": "pymongo-4.11.3.tar.gz"}]} @@ -160,6 +160,7 @@ {"info": {"classifiers": ["Development Status :: 6 - Mature", "Framework :: Pyramid", "Intended Audience :: Developers", "License :: Repoze Public License", "Programming Language :: Python", "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 :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: WSGI"], "name": "pyramid", "requires_python": "", "version": "1.7.6", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pyramid-1.7.6-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pyramid-1.7.6.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 6 - Mature", "Framework :: Pyramid", "Intended Audience :: Developers", "License :: Repoze Public License", "Programming Language :: Python", "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 :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: WSGI"], "name": "pyramid", "requires_python": "", "version": "1.8.6", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pyramid-1.8.6-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "pyramid-1.8.6.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.6", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp311-cp311-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp311-cp311-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp311-cp311-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp311-cp311-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp311-cp311-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp312-cp312-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp312-cp312-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp312-cp312-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp312-cp312-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp312-cp312-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp313-cp313-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp313-cp313-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp313-cp313-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp313-cp313-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp313-cp313-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp314-cp314-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp314-cp314-musllinux_1_1_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp314-cp314-musllinux_1_1_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp314-cp314-musllinux_1_1_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp314-cp314-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "pyreqwest-0.11.6-cp314-cp314-win_arm64.whl"}, {"packagetype": "sdist", "filename": "pyreqwest-0.11.6.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 :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "pyspark", "requires_python": "", "version": "2.1.3", "yanked": false}, "urls": [{"packagetype": "sdist", "filename": "pyspark-2.1.3.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 :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "pyspark", "requires_python": "", "version": "2.4.8", "yanked": false}, "urls": [{"packagetype": "sdist", "filename": "pyspark-2.4.8.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"}]} @@ -171,7 +172,7 @@ {"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.46.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp310-cp310-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp310-cp310-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp310-cp310-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp311-cp311-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp311-cp311-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp311-cp311-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp312-cp312-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp312-cp312-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp312-cp312-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp313-cp313-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp313-cp313-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp313-cp313-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp39-cp39-macosx_10_15_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp39-cp39-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp39-cp39-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.0-cp39-cp39-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.46.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.51.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp310-cp310-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp310-cp310-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp310-cp310-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp311-cp311-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp311-cp311-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp311-cp311-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp312-cp312-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp312-cp312-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp312-cp312-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp313-cp313-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp313-cp313-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp313-cp313-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp39-cp39-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp39-cp39-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.2-cp39-cp39-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.51.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", "Programming Language :: Python :: 3.9"], "name": "ray", "requires_python": ">=3.9", "version": "2.53.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp310-cp310-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp310-cp310-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp310-cp310-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp311-cp311-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp311-cp311-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp311-cp311-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp312-cp312-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp312-cp312-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp312-cp312-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp313-cp313-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-cp313-cp313-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.53.0-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"], "name": "ray", "requires_python": ">=3.10", "version": "2.54.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp310-cp310-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp310-cp310-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp310-cp310-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp311-cp311-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp311-cp311-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp311-cp311-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp312-cp312-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp312-cp312-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp312-cp312-manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp313-cp313-macosx_12_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-cp313-cp313-manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "ray-2.54.0-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"], "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.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 :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python"], "name": "redis", "requires_python": null, "version": "0.6.1", "yanked": false}, "urls": [{"packagetype": "sdist", "filename": "redis-0.6.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 :: 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"], "name": "redis", "requires_python": "", "version": "2.10.6", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "redis-2.10.6-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "redis-2.10.6.tar.gz"}]} @@ -183,7 +184,8 @@ {"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.3.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "redis-7.3.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "redis-7.3.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.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "redis-7.4.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "redis-7.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": "8.0.0b1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "redis-8.0.0b1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "redis-8.0.0b1.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 3 - Alpha", "Environment :: Web Environment", "Operating System :: POSIX", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4"], "name": "redis-py-cluster", "requires_python": null, "version": "0.1.0", "yanked": false}, "urls": [{"packagetype": "sdist", "filename": "redis-py-cluster-0.1.0.tar.gz"}]} {"info": {"classifiers": [], "name": "redis-py-cluster", "requires_python": null, "version": "1.1.0", "yanked": false}, "urls": [{"packagetype": "sdist", "filename": "redis-py-cluster-1.1.0.tar.gz"}]} {"info": {"classifiers": [], "name": "redis-py-cluster", "requires_python": null, "version": "1.2.0", "yanked": false}, "urls": [{"packagetype": "sdist", "filename": "redis-py-cluster-1.2.0.tar.gz"}]} @@ -191,11 +193,11 @@ {"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "License :: OSI Approved :: MIT License", "Operating System :: POSIX", "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"], "name": "redis-py-cluster", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", "version": "2.0.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "redis_py_cluster-2.0.0-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "redis-py-cluster-2.0.0.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "License :: OSI Approved :: MIT License", "Operating System :: POSIX", "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": "redis-py-cluster", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4", "version": "2.1.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "redis_py_cluster-2.1.3-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "redis-py-cluster-2.1.3.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.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3"], "name": "requests", "requires_python": null, "version": "2.0.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "requests-2.0.1-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "requests-2.0.1.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.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 :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "requests", "requires_python": null, "version": "2.10.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "requests-2.10.0-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "requests-2.10.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.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 :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy"], "name": "requests", "requires_python": null, "version": "2.11.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "requests-2.11.1-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "requests-2.11.1.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.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"], "name": "requests", "requires_python": "", "version": "2.12.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "requests-2.12.5-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "requests-2.12.5.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.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"], "name": "requests", "requires_python": "", "version": "2.16.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "requests-2.16.5-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "requests-2.16.5.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.9", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries"], "name": "requests", "requires_python": ">=3.9", "version": "2.32.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "requests-2.32.5-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "requests-2.32.5.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.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"], "name": "requests", "requires_python": "", "version": "2.13.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "requests-2.13.0-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "requests-2.13.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.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"], "name": "requests", "requires_python": "", "version": "2.17.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "requests-2.17.3-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "requests-2.17.3.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 :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Internet :: WWW/HTTP", "Topic :: Software Development :: Libraries"], "name": "requests", "requires_python": ">=3.10", "version": "2.33.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "requests-2.33.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "requests-2.33.1.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.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5"], "name": "requests", "requires_python": null, "version": "2.8.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "requests-2.8.1-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "requests-2.8.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 :: 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 :: 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": "", "version": "0.13.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "rq-0.13.0-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "rq-0.13.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 :: 2", "Programming Language :: Python :: 3", "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": "", "version": "0.6.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "rq-0.6.0-py2.py3-none-any.whl"}, {"packagetype": "sdist", "filename": "rq-0.6.0.tar.gz"}]} @@ -210,17 +212,14 @@ {"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.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "sanic-25.12.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "sanic-25.12.0.tar.gz"}]} {"info": {"classifiers": ["Development Status :: 3 - Alpha", "Environment :: Web Environment", "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.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Internet :: WWW/HTTP"], "name": "starlette", "requires_python": ">=3.6", "version": "0.16.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "starlette-0.16.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "starlette-0.16.0.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.11", "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.28.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "starlette-0.28.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "starlette-0.28.0.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.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"], "name": "starlette", "requires_python": ">=3.8", "version": "0.40.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "starlette-0.40.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "starlette-0.40.0.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.0.0rc1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "starlette-1.0.0rc1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "starlette-1.0.0rc1.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.0.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "starlette-1.0.0-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "starlette-1.0.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.71.6", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "statsig-0.71.6-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "statsig-0.71.6.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", "License :: OSI Approved :: MIT License", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules"], "name": "strawberry-graphql", "requires_python": "<4.0,>=3.10", "version": "0.311.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "strawberry_graphql-0.311.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "strawberry_graphql-0.311.3.tar.gz"}]} -{"info": {"classifiers": ["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": "temporalio", "requires_python": ">=3.10", "version": "1.20.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "temporalio-1.20.0-cp310-abi3-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "temporalio-1.20.0-cp310-abi3-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "temporalio-1.20.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "temporalio-1.20.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "temporalio-1.20.0-cp310-abi3-win_amd64.whl"}, {"packagetype": "sdist", "filename": "temporalio-1.20.0.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.314.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "strawberry_graphql-0.314.3-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "strawberry_graphql-0.314.3.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.9", "Topic :: Scientific/Engineering :: Artificial Intelligence"], "name": "tokenizers", "requires_python": ">=3.9", "version": "0.22.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-cp39-abi3-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "tokenizers-0.22.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl"}, {"packagetype": "sdist", "filename": "tokenizers-0.22.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.5", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.5-cp39-abi3-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.5-cp39-abi3-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "tornado-6.5.5-cp39-abi3-win_arm64.whl"}, {"packagetype": "sdist", "filename": "tornado-6.5.5.tar.gz"}]} @@ -236,6 +235,5 @@ {"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.6", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "trytond-7.8.6-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "trytond-7.8.6.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.24.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "typer-0.24.1-py3-none-any.whl"}, {"packagetype": "sdist", "filename": "typer-0.24.1.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", "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 :: Rust"], "name": "uuid_utils", "requires_python": ">=3.9", "version": "0.14.0", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-cp39-abi3-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-pp311-pypy311_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "sdist", "filename": "uuid_utils-0.14.0.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 :: 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 :: Rust"], "name": "uuid_utils", "requires_python": ">=3.9", "version": "0.14.1", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-musllinux_1_2_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-musllinux_1_2_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-musllinux_1_2_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-musllinux_1_2_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-win32.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-cp39-abi3-win_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-pp311-pypy311_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-pp311-pypy311_pp73-macosx_10_12_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "uuid_utils-0.14.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl"}, {"packagetype": "sdist", "filename": "uuid_utils-0.14.1.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 :: 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": "zope.interface", "requires_python": ">=3.10", "version": "8.2", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp312-cp312-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp313-cp313-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp314-cp314-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp314-cp314-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.2-cp314-cp314-win_amd64.whl"}, {"packagetype": "sdist", "filename": "zope_interface-8.2.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 :: 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": "zope.interface", "requires_python": ">=3.10", "version": "8.3", "yanked": false}, "urls": [{"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp310-cp310-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp310-cp310-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp310-cp310-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp311-cp311-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp311-cp311-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp311-cp311-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp312-cp312-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp312-cp312-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp312-cp312-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp313-cp313-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp313-cp313-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp313-cp313-win_amd64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp314-cp314-macosx_10_9_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp314-cp314-macosx_11_0_arm64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp314-cp314-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl"}, {"packagetype": "bdist_wheel", "filename": "zope_interface-8.3-cp314-cp314-win_amd64.whl"}, {"packagetype": "sdist", "filename": "zope_interface-8.3.tar.gz"}]} diff --git a/scripts/populate_tox/tox.jinja b/scripts/populate_tox/tox.jinja index 6a6d1a54c9..e386d87f1c 100755 --- a/scripts/populate_tox/tox.jinja +++ b/scripts/populate_tox/tox.jinja @@ -78,14 +78,17 @@ deps = linters: -r requirements-linting.txt linters: werkzeug<2.3.0 + linters: httpcore[asyncio] mypy: -r requirements-linting.txt mypy: werkzeug<2.3.0 + mypy: httpcore[asyncio] ruff: -r requirements-linting.txt # === Common === py3.8-common: hypothesis common: pytest-asyncio + common: httpcore[asyncio] # 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 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 e8f2b5dfe2..122a02065d 100755 --- a/scripts/split_tox_gh_actions/split_tox_gh_actions.py +++ b/scripts/split_tox_gh_actions/split_tox_gh_actions.py @@ -124,6 +124,7 @@ "Network": [ "grpc", "httpx", + "pyreqwest", "requests", ], "Tasks": [ diff --git a/scripts/split_tox_gh_actions/templates/test_group.jinja b/scripts/split_tox_gh_actions/templates/test_group.jinja index bec1a0f835..4b8f981789 100644 --- a/scripts/split_tox_gh_actions/templates/test_group.jinja +++ b/scripts/split_tox_gh_actions/templates/test_group.jinja @@ -42,8 +42,8 @@ # Use Docker container only for Python 3.6 {% raw %}container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }}{% endraw %} steps: - - uses: actions/checkout@v6.0.2 - - uses: actions/setup-python@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 {% raw %}if: ${{ matrix.python-version != '3.6' }}{% endraw %} with: python-version: {% raw %}${{ matrix.python-version }}{% endraw %} @@ -51,17 +51,17 @@ {% if needs_clickhouse %} - name: "Setup ClickHouse Server" - uses: getsentry/action-clickhouse-in-ci@v1.7 + uses: getsentry/action-clickhouse-in-ci@5dc8a6a50d689bd6051db0241f34849e5a36490b # v1.7 {% endif %} {% if needs_redis %} - name: Start Redis - uses: supercharge/redis-github-action@v2 + uses: supercharge/redis-github-action@87f27ff1ab2d9e62db54b11ee5e7f78ff18f8933 # v2 {% endif %} {% if needs_java %} - name: Install Java - uses: actions/setup-java@v5 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 with: distribution: 'temurin' java-version: '21' @@ -96,9 +96,10 @@ - name: Parse and Upload Coverage if: {% raw %}${{ !cancelled() }}{% endraw %} - uses: getsentry/codecov-action@main + uses: getsentry/codecov-action@fda17cfc37e16a0cc23f61685813390bfee7daf3 # main with: token: {% raw %}${{ secrets.GITHUB_TOKEN }}{% endraw %} files: coverage.xml junit-xml-pattern: .junitxml + base-branch: master verbose: true diff --git a/sentry_sdk/__init__.py b/sentry_sdk/__init__.py index fda2f18dd1..7fd0e1953d 100644 --- a/sentry_sdk/__init__.py +++ b/sentry_sdk/__init__.py @@ -25,6 +25,7 @@ "configure_scope", "continue_trace", "flush", + "flush_async", "get_baggage", "get_client", "get_global_scope", diff --git a/sentry_sdk/_span_batcher.py b/sentry_sdk/_span_batcher.py index 967011c083..426d5d9629 100644 --- a/sentry_sdk/_span_batcher.py +++ b/sentry_sdk/_span_batcher.py @@ -91,13 +91,21 @@ def add(self, span: "StreamedSpan") -> None: @staticmethod def _estimate_size(item: "StreamedSpan") -> int: # Rough estimate of serialized span size that's quick to compute. - # 210 is the rough size of the payload without attributes, and we - # estimate additional 70 bytes on top of that per attribute. - return 210 + 70 * len(item._attributes) + # 210 is the rough size of the payload without attributes, and then we + # estimate the attributes separately. + estimate = 210 + for value in item._attributes.values(): + estimate += 50 + + if isinstance(value, str): + estimate += len(value) + else: + estimate += len(str(value)) + + return estimate @staticmethod def _to_transport_format(item: "StreamedSpan") -> "Any": - # TODO[span-first] res: "dict[str, Any]" = { "trace_id": item.trace_id, "span_id": item.span_id, @@ -126,7 +134,7 @@ def _flush(self) -> None: return envelopes = [] - for trace_id, spans in self._span_buffer.items(): + for spans in self._span_buffer.values(): if spans: dsc = spans[0]._dynamic_sampling_context() diff --git a/sentry_sdk/_werkzeug.py b/sentry_sdk/_werkzeug.py index cdc3026c08..1fa58f632b 100644 --- a/sentry_sdk/_werkzeug.py +++ b/sentry_sdk/_werkzeug.py @@ -38,6 +38,7 @@ from typing import Dict from typing import Iterator from typing import Tuple + from typing import Optional # @@ -62,35 +63,41 @@ def _get_headers(environ: "Dict[str, str]") -> "Iterator[Tuple[str, str]]": yield key.replace("_", "-").title(), value -# +def _strip_default_port(host: str, scheme: "Optional[str]") -> str: + """Strip the port from the host if it's the default for the scheme.""" + if scheme == "http" and host.endswith(":80"): + return host[:-3] + if scheme == "https" and host.endswith(":443"): + return host[:-4] + return host + + # `get_host` comes from `werkzeug.wsgi.get_host` # https://github.com/pallets/werkzeug/blob/1.0.1/src/werkzeug/wsgi.py#L145 -# + + def get_host(environ: "Dict[str, str]", use_x_forwarded_for: bool = False) -> str: """ Return the host for the given WSGI environment. """ + scheme = environ.get("wsgi.url_scheme") + if use_x_forwarded_for: + scheme = environ.get("HTTP_X_FORWARDED_PROTO", scheme) + if use_x_forwarded_for and "HTTP_X_FORWARDED_HOST" in environ: - rv = environ["HTTP_X_FORWARDED_HOST"] - if environ["wsgi.url_scheme"] == "http" and rv.endswith(":80"): - rv = rv[:-3] - elif environ["wsgi.url_scheme"] == "https" and rv.endswith(":443"): - rv = rv[:-4] + return _strip_default_port(environ["HTTP_X_FORWARDED_HOST"], scheme) elif environ.get("HTTP_HOST"): - rv = environ["HTTP_HOST"] - if environ["wsgi.url_scheme"] == "http" and rv.endswith(":80"): - rv = rv[:-3] - elif environ["wsgi.url_scheme"] == "https" and rv.endswith(":443"): - rv = rv[:-4] + return _strip_default_port(environ["HTTP_HOST"], scheme) elif environ.get("SERVER_NAME"): + # SERVER_NAME/SERVER_PORT describe the internal server, so use + # wsgi.url_scheme (not the forwarded scheme) for port decisions. rv = environ["SERVER_NAME"] if (environ["wsgi.url_scheme"], environ["SERVER_PORT"]) not in ( ("https", "443"), ("http", "80"), ): rv += ":" + environ["SERVER_PORT"] + return rv else: # In spite of the WSGI spec, SERVER_NAME might not be present. - rv = "unknown" - - return rv + return "unknown" diff --git a/sentry_sdk/ai/consts.py b/sentry_sdk/ai/consts.py new file mode 100644 index 0000000000..35ee4bd788 --- /dev/null +++ b/sentry_sdk/ai/consts.py @@ -0,0 +1,6 @@ +import re + +# Matches data URLs with base64-encoded content, e.g. "data:image/png;base64,iVBORw0K..." +DATA_URL_BASE64_REGEX = re.compile( + r"^data:(?:[a-zA-Z0-9][a-zA-Z0-9.+\-]*/[a-zA-Z0-9][a-zA-Z0-9.+\-]*)(?:;[a-zA-Z0-9\-]+=[^;,]*)*;base64,(?:[A-Za-z0-9+/\-_]+={0,2})$" +) diff --git a/sentry_sdk/ai/utils.py b/sentry_sdk/ai/utils.py index 3cfae61546..4103736969 100644 --- a/sentry_sdk/ai/utils.py +++ b/sentry_sdk/ai/utils.py @@ -4,6 +4,7 @@ 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 @@ -588,6 +589,20 @@ def _find_truncation_index(messages: "List[Dict[str, Any]]", max_bytes: int) -> 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 = item.get("image_url", {}).get("url", "") + 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]]": @@ -640,7 +655,9 @@ def redact_blob_message_parts( content = message.get("content") if isinstance(content, list): for item in content: - if isinstance(item, dict) and item.get("type") == "blob": + if isinstance(item, dict) and ( + item.get("type") == "blob" or _is_image_type_with_blob_content(item) + ): has_blobs = True break if has_blobs: @@ -661,8 +678,11 @@ def redact_blob_message_parts( content = message.get("content") if isinstance(content, list): for item in content: - if isinstance(item, dict) and item.get("type") == "blob": - item["content"] = BLOB_DATA_SUBSTITUTE + if isinstance(item, dict): + if item.get("type") == "blob": + item["content"] = BLOB_DATA_SUBSTITUTE + elif _is_image_type_with_blob_content(item): + item["image_url"]["url"] = BLOB_DATA_SUBSTITUTE return messages_copy diff --git a/sentry_sdk/api.py b/sentry_sdk/api.py index a9936230ad..105f531e5f 100644 --- a/sentry_sdk/api.py +++ b/sentry_sdk/api.py @@ -60,6 +60,7 @@ def overload(x: "T") -> "T": "configure_scope", "continue_trace", "flush", + "flush_async", "get_baggage", "get_client", "get_global_scope", @@ -351,6 +352,14 @@ def flush( return get_client().flush(timeout=timeout, callback=callback) +@clientmethod +async def flush_async( + timeout: "Optional[float]" = None, + callback: "Optional[Callable[[int, float], None]]" = None, +) -> None: + return await get_client().flush_async(timeout=timeout, callback=callback) + + @scopemethod def start_span( **kwargs: "Any", diff --git a/sentry_sdk/client.py b/sentry_sdk/client.py index 9aa26a4f30..9f795d2489 100644 --- a/sentry_sdk/client.py +++ b/sentry_sdk/client.py @@ -31,7 +31,11 @@ from sentry_sdk.serializer import serialize from sentry_sdk.tracing import trace from sentry_sdk.tracing_utils import has_span_streaming_enabled -from sentry_sdk.transport import BaseHttpTransport, make_transport +from sentry_sdk.transport import ( + HttpTransportCore, + make_transport, + AsyncHttpTransport, +) from sentry_sdk.consts import ( SPANDATA, DEFAULT_MAX_VALUE_LENGTH, @@ -251,6 +255,12 @@ def close(self, *args: "Any", **kwargs: "Any") -> None: def flush(self, *args: "Any", **kwargs: "Any") -> None: return None + async def close_async(self, *args: "Any", **kwargs: "Any") -> None: + return None + + async def flush_async(self, *args: "Any", **kwargs: "Any") -> None: + return None + def __enter__(self) -> "BaseClient": return self @@ -472,7 +482,7 @@ def _record_lost_event( or self.metrics_batcher or self.span_batcher or has_profiling_enabled(self.options) - or isinstance(self.transport, BaseHttpTransport) + or isinstance(self.transport, HttpTransportCore) ): # If we have anything on that could spawn a background thread, we # need to check if it's safe to use them. @@ -999,6 +1009,32 @@ def get_integration( return self.integrations.get(integration_name) + def _has_async_transport(self) -> bool: + """Check if the current transport is async.""" + return isinstance(self.transport, AsyncHttpTransport) + + @property + def _batchers(self) -> "tuple[Any, ...]": + return tuple( + b + for b in (self.log_batcher, self.metrics_batcher, self.span_batcher) + if b is not None + ) + + def _close_components(self) -> None: + """Kill all client components in the correct order.""" + self.session_flusher.kill() + for b in self._batchers: + b.kill() + if self.monitor: + self.monitor.kill() + + def _flush_components(self) -> None: + """Flush all client components.""" + self.session_flusher.flush() + for b in self._batchers: + b.flush() + def close( self, timeout: "Optional[float]" = None, @@ -1009,19 +1045,40 @@ def close( semantics as :py:meth:`Client.flush`. """ if self.transport is not None: - self.flush(timeout=timeout, callback=callback) - self.session_flusher.kill() - if self.log_batcher is not None: - self.log_batcher.kill() - if self.metrics_batcher is not None: - self.metrics_batcher.kill() - if self.span_batcher is not None: - self.span_batcher.kill() - if self.monitor: - self.monitor.kill() + if self._has_async_transport(): + warnings.warn( + "close() used with AsyncHttpTransport. Use close_async() instead.", + stacklevel=2, + ) + self._flush_components() + else: + self.flush(timeout=timeout, callback=callback) + self._close_components() self.transport.kill() self.transport = None + async def close_async( + self, + timeout: "Optional[float]" = None, + callback: "Optional[Callable[[int, float], None]]" = None, + ) -> None: + """ + Asynchronously close the client and shut down the transport. Arguments have the same + semantics as :py:meth:`Client.flush_async`. + """ + if self.transport is not None: + if not self._has_async_transport(): + logger.debug( + "close_async() used with non-async transport, aborting. Please use close() instead." + ) + return + await self.flush_async(timeout=timeout, callback=callback) + self._close_components() + kill_task = self.transport.kill() # type: ignore + if kill_task is not None: + await kill_task + self.transport = None + def flush( self, timeout: "Optional[float]" = None, @@ -1035,23 +1092,55 @@ def flush( :param callback: Is invoked with the number of pending events and the configured timeout. """ if self.transport is not None: + if self._has_async_transport(): + warnings.warn( + "flush() used with AsyncHttpTransport. Use flush_async() instead.", + stacklevel=2, + ) + return if timeout is None: timeout = self.options["shutdown_timeout"] - self.session_flusher.flush() - if self.log_batcher is not None: - self.log_batcher.flush() - if self.metrics_batcher is not None: - self.metrics_batcher.flush() - if self.span_batcher is not None: - self.span_batcher.flush() + self._flush_components() + self.transport.flush(timeout=timeout, callback=callback) + async def flush_async( + self, + timeout: "Optional[float]" = None, + callback: "Optional[Callable[[int, float], None]]" = None, + ) -> None: + """ + Asynchronously wait for the current events to be sent. + + :param timeout: Wait for at most `timeout` seconds. If no `timeout` is provided, the `shutdown_timeout` option value is used. + + :param callback: Is invoked with the number of pending events and the configured timeout. + """ + if self.transport is not None: + if not self._has_async_transport(): + logger.debug( + "flush_async() used with non-async transport, aborting. Please use flush() instead." + ) + return + if timeout is None: + timeout = self.options["shutdown_timeout"] + self._flush_components() + flush_task = self.transport.flush(timeout=timeout, callback=callback) # type: ignore + if flush_task is not None: + await flush_task + def __enter__(self) -> "_Client": return self def __exit__(self, exc_type: "Any", exc_value: "Any", tb: "Any") -> None: self.close() + async def __aenter__(self) -> "_Client": + return self + + async def __aexit__(self, exc_type: "Any", exc_value: "Any", tb: "Any") -> None: + await self.close_async() + from typing import TYPE_CHECKING diff --git a/sentry_sdk/consts.py b/sentry_sdk/consts.py index 7c4e2ff2fc..25a50a12b2 100644 --- a/sentry_sdk/consts.py +++ b/sentry_sdk/consts.py @@ -78,6 +78,7 @@ class CompressionAlgo(Enum): "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], @@ -440,6 +441,12 @@ class SPANDATA: Example: myDatabase """ + DB_DRIVER_NAME = "db.driver.name" + """ + The name of the database driver being used for the connection. + Example: "psycopg2" + """ + DB_OPERATION = "db.operation" """ The name of the operation being executed, e.g. the MongoDB command name such as findAndModify, or the SQL keyword. @@ -635,12 +642,6 @@ class SPANDATA: Example: "rainy, 57Β°F" """ - GEN_AI_TOOL_TYPE = "gen_ai.tool.type" - """ - The type of tool being used. - Example: "function" - """ - GEN_AI_USAGE_INPUT_TOKENS = "gen_ai.usage.input_tokens" """ The number of tokens in the input. @@ -921,9 +922,8 @@ class OP: GEN_AI_CREATE_AGENT = "gen_ai.create_agent" GEN_AI_EMBEDDINGS = "gen_ai.embeddings" GEN_AI_EXECUTE_TOOL = "gen_ai.execute_tool" - GEN_AI_GENERATE_TEXT = "gen_ai.generate_text" + GEN_AI_TEXT_COMPLETION = "gen_ai.text_completion" GEN_AI_HANDOFF = "gen_ai.handoff" - GEN_AI_PIPELINE = "gen_ai.pipeline" GEN_AI_INVOKE_AGENT = "gen_ai.invoke_agent" GEN_AI_RESPONSES = "gen_ai.responses" GRAPHQL_EXECUTE = "graphql.execute" @@ -1492,4 +1492,4 @@ def _get_default_options() -> "dict[str, Any]": del _get_default_options -VERSION = "2.55.0" +VERSION = "2.58.0" diff --git a/sentry_sdk/integrations/__init__.py b/sentry_sdk/integrations/__init__.py index dd12a6011f..599f0507d0 100644 --- a/sentry_sdk/integrations/__init__.py +++ b/sentry_sdk/integrations/__init__.py @@ -150,6 +150,7 @@ def iter_default_integrations( "openfeature": (0, 7, 1), "pydantic_ai": (1, 0, 0), "pymongo": (3, 5, 0), + "pyreqwest": (0, 11, 6), "quart": (0, 16, 0), "ray": (2, 7, 0), "requests": (2, 0, 0), diff --git a/sentry_sdk/integrations/_asgi_common.py b/sentry_sdk/integrations/_asgi_common.py index a8022c6bb1..525ca4b5b5 100644 --- a/sentry_sdk/integrations/_asgi_common.py +++ b/sentry_sdk/integrations/_asgi_common.py @@ -105,3 +105,35 @@ def _get_request_data(asgi_scope: "Any") -> "Dict[str, Any]": request_data["env"] = {"REMOTE_ADDR": _get_ip(asgi_scope)} return request_data + + +def _get_request_attributes(asgi_scope: "Any") -> "dict[str, Any]": + """ + Return attributes related to the HTTP request from the ASGI scope. + """ + attributes: "dict[str, Any]" = {} + + ty = asgi_scope["type"] + if ty in ("http", "websocket"): + if asgi_scope.get("method"): + attributes["http.request.method"] = asgi_scope["method"].upper() + + headers = _filter_headers(_get_headers(asgi_scope), use_annotated_value=False) + for header, value in headers.items(): + attributes[f"http.request.header.{header.lower()}"] = value + + query = _get_query(asgi_scope) + if query: + attributes["http.query"] = query + + attributes["url.full"] = _get_url( + asgi_scope, "http" if ty == "http" else "ws", headers.get("host") + ) + + client = asgi_scope.get("client") + if client and should_send_default_pii(): + ip = _get_ip(asgi_scope) + attributes["client.address"] = ip + attributes["user.ip_address"] = ip + + return attributes diff --git a/sentry_sdk/integrations/_wsgi_common.py b/sentry_sdk/integrations/_wsgi_common.py index 688e965be4..9f1b1399f0 100644 --- a/sentry_sdk/integrations/_wsgi_common.py +++ b/sentry_sdk/integrations/_wsgi_common.py @@ -3,6 +3,7 @@ from copy import deepcopy import sentry_sdk +from sentry_sdk._types import SENSITIVE_DATA_SUBSTITUTE from sentry_sdk.scope import should_send_default_pii from sentry_sdk.utils import AnnotatedValue, logger @@ -211,16 +212,19 @@ def _is_json_content_type(ct: "Optional[str]") -> bool: def _filter_headers( headers: "Mapping[str, str]", + use_annotated_value: bool = True, ) -> "Mapping[str, Union[AnnotatedValue, str]]": if should_send_default_pii(): return headers + substitute: "Union[AnnotatedValue, str]" + if use_annotated_value: + substitute = AnnotatedValue.removed_because_over_size_limit() + else: + substitute = SENSITIVE_DATA_SUBSTITUTE + return { - k: ( - v - if k.upper().replace("-", "_") not in SENSITIVE_HEADERS - else AnnotatedValue.removed_because_over_size_limit() - ) + k: (v if k.upper().replace("-", "_") not in SENSITIVE_HEADERS else substitute) for k, v in headers.items() } diff --git a/sentry_sdk/integrations/anthropic.py b/sentry_sdk/integrations/anthropic.py index 40c1fa0635..efc2f70ffd 100644 --- a/sentry_sdk/integrations/anthropic.py +++ b/sentry_sdk/integrations/anthropic.py @@ -14,10 +14,9 @@ get_start_span_function, transform_anthropic_content_part, ) -from sentry_sdk.consts import OP, SPANDATA, SPANSTATUS +from sentry_sdk.consts import OP, SPANDATA from sentry_sdk.integrations import _check_minimum_version, DidNotEnable, Integration from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.tracing_utils import set_span_errored from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, @@ -195,8 +194,6 @@ def setup_once() -> None: def _capture_exception(exc: "Any") -> None: - set_span_errored() - event, hint = event_from_exception( exc, client_options=sentry_sdk.get_client().options, @@ -600,7 +597,10 @@ def _set_output_data( ) -def _sentry_patched_create_common(f: "Any", *args: "Any", **kwargs: "Any") -> "Any": +def _sentry_patched_create_sync(f: "Any", *args: "Any", **kwargs: "Any") -> "Any": + """ + Creates and manages an AI Client Span for both non-streaming and streaming calls. + """ integration = kwargs.pop("integration") if integration is None: return f(*args, **kwargs) @@ -624,7 +624,14 @@ def _sentry_patched_create_common(f: "Any", *args: "Any", **kwargs: "Any") -> "A _set_create_input_data(span, kwargs, integration) - result = yield f, args, kwargs + try: + result = f(*args, **kwargs) + except Exception as exc: + exc_info = sys.exc_info() + with capture_internal_exceptions(): + _capture_exception(exc) + span.__exit__(*exc_info) + reraise(*exc_info) if isinstance(result, Stream): result._span = span @@ -638,6 +645,82 @@ def _sentry_patched_create_common(f: "Any", *args: "Any", **kwargs: "Any") -> "A return result + with capture_internal_exceptions(): + if hasattr(result, "content"): + ( + input_tokens, + output_tokens, + cache_read_input_tokens, + cache_write_input_tokens, + ) = _get_token_usage(result) + + content_blocks = [] + for content_block in result.content: + if hasattr(content_block, "to_dict"): + content_blocks.append(content_block.to_dict()) + elif hasattr(content_block, "model_dump"): + content_blocks.append(content_block.model_dump()) + elif hasattr(content_block, "text"): + content_blocks.append({"type": "text", "text": content_block.text}) + + _set_output_data( + span=span, + integration=integration, + model=getattr(result, "model", None), + input_tokens=input_tokens, + output_tokens=output_tokens, + cache_read_input_tokens=cache_read_input_tokens, + cache_write_input_tokens=cache_write_input_tokens, + content_blocks=content_blocks, + response_id=getattr(result, "id", None), + finish_reason=getattr(result, "stop_reason", None), + ) + span.__exit__(None, None, None) + else: + span.set_data("unknown_response", True) + span.__exit__(None, None, None) + + return result + + +async def _sentry_patched_create_async( + f: "Any", *args: "Any", **kwargs: "Any" +) -> "Any": + """ + Creates and manages an AI Client Span for both non-streaming and streaming calls. + """ + integration = kwargs.pop("integration") + if integration is None: + return await f(*args, **kwargs) + + if "messages" not in kwargs: + return await f(*args, **kwargs) + + try: + iter(kwargs["messages"]) + except TypeError: + return await f(*args, **kwargs) + + model = kwargs.get("model", "") + + span = get_start_span_function()( + op=OP.GEN_AI_CHAT, + name=f"chat {model}".strip(), + origin=AnthropicIntegration.origin, + ) + span.__enter__() + + _set_create_input_data(span, kwargs, integration) + + try: + result = await f(*args, **kwargs) + except Exception as exc: + exc_info = sys.exc_info() + with capture_internal_exceptions(): + _capture_exception(exc) + span.__exit__(*exc_info) + reraise(*exc_info) + if isinstance(result, AsyncStream): result._span = span result._integration = integration @@ -689,41 +772,14 @@ def _sentry_patched_create_common(f: "Any", *args: "Any", **kwargs: "Any") -> "A def _wrap_message_create(f: "Any") -> "Any": - def _execute_sync(f: "Any", *args: "Any", **kwargs: "Any") -> "Any": - gen = _sentry_patched_create_common(f, *args, **kwargs) - - try: - f, args, kwargs = next(gen) - except StopIteration as e: - return e.value - - try: - try: - result = f(*args, **kwargs) - except Exception as exc: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - _capture_exception(exc) - reraise(*exc_info) - - return gen.send(result) - except StopIteration as e: - return e.value - @wraps(f) - def _sentry_patched_create_sync(*args: "Any", **kwargs: "Any") -> "Any": + def _sentry_wrapped_create_sync(*args: "Any", **kwargs: "Any") -> "Any": integration = sentry_sdk.get_client().get_integration(AnthropicIntegration) kwargs["integration"] = integration - try: - return _execute_sync(f, *args, **kwargs) - finally: - span = sentry_sdk.get_current_span() - if span is not None and span.status == SPANSTATUS.INTERNAL_ERROR: - with capture_internal_exceptions(): - span.__exit__(None, None, None) + return _sentry_patched_create_sync(f, *args, **kwargs) - return _sentry_patched_create_sync + return _sentry_wrapped_create_sync def _initialize_data_accumulation_state(stream: "Union[Stream, MessageStream]") -> None: @@ -810,41 +866,14 @@ def close(self: "Union[Stream, MessageStream]") -> None: def _wrap_message_create_async(f: "Any") -> "Any": - async def _execute_async(f: "Any", *args: "Any", **kwargs: "Any") -> "Any": - gen = _sentry_patched_create_common(f, *args, **kwargs) - - try: - f, args, kwargs = next(gen) - except StopIteration as e: - return await e.value - - try: - try: - result = await f(*args, **kwargs) - except Exception as exc: - exc_info = sys.exc_info() - with capture_internal_exceptions(): - _capture_exception(exc) - reraise(*exc_info) - - return gen.send(result) - except StopIteration as e: - return e.value - @wraps(f) - async def _sentry_patched_create_async(*args: "Any", **kwargs: "Any") -> "Any": + async def _sentry_wrapped_create_async(*args: "Any", **kwargs: "Any") -> "Any": integration = sentry_sdk.get_client().get_integration(AnthropicIntegration) kwargs["integration"] = integration - try: - return await _execute_async(f, *args, **kwargs) - finally: - span = sentry_sdk.get_current_span() - if span is not None and span.status == SPANSTATUS.INTERNAL_ERROR: - with capture_internal_exceptions(): - span.__exit__(None, None, None) + return await _sentry_patched_create_async(f, *args, **kwargs) - return _sentry_patched_create_async + return _sentry_wrapped_create_async def _wrap_async_close( @@ -892,22 +921,21 @@ def _wrap_message_stream_manager_enter(f: "Any") -> "Any": @wraps(f) def _sentry_patched_enter(self: "MessageStreamManager") -> "MessageStream": - stream = f(self) if not hasattr(self, "_max_tokens"): - return stream + return f(self) integration = sentry_sdk.get_client().get_integration(AnthropicIntegration) if integration is None: - return stream + return f(self) if self._messages is None: - return stream + return f(self) try: iter(self._messages) except TypeError: - return stream + return f(self) span = get_start_span_function()( op=OP.GEN_AI_CHAT, @@ -930,6 +958,15 @@ def _sentry_patched_enter(self: "MessageStreamManager") -> "MessageStream": tools=self._tools, ) + try: + stream = f(self) + except Exception as exc: + exc_info = sys.exc_info() + with capture_internal_exceptions(): + _capture_exception(exc) + span.__exit__(*exc_info) + reraise(*exc_info) + stream._span = span stream._integration = integration @@ -979,22 +1016,21 @@ def _wrap_async_message_stream_manager_aenter(f: "Any") -> "Any": async def _sentry_patched_aenter( self: "AsyncMessageStreamManager", ) -> "AsyncMessageStream": - stream = await f(self) if not hasattr(self, "_max_tokens"): - return stream + return await f(self) integration = sentry_sdk.get_client().get_integration(AnthropicIntegration) if integration is None: - return stream + return await f(self) if self._messages is None: - return stream + return await f(self) try: iter(self._messages) except TypeError: - return stream + return await f(self) span = get_start_span_function()( op=OP.GEN_AI_CHAT, @@ -1017,6 +1053,15 @@ async def _sentry_patched_aenter( tools=self._tools, ) + try: + stream = await f(self) + except Exception as exc: + exc_info = sys.exc_info() + with capture_internal_exceptions(): + _capture_exception(exc) + span.__exit__(*exc_info) + reraise(*exc_info) + stream._span = span stream._integration = integration diff --git a/sentry_sdk/integrations/asgi.py b/sentry_sdk/integrations/asgi.py index 2294781f05..64dc3cc554 100644 --- a/sentry_sdk/integrations/asgi.py +++ b/sentry_sdk/integrations/asgi.py @@ -15,6 +15,7 @@ from sentry_sdk.consts import OP from sentry_sdk.integrations._asgi_common import ( _get_headers, + _get_request_attributes, _get_request_data, _get_url, ) @@ -23,7 +24,11 @@ nullcontext, ) from sentry_sdk.sessions import track_session -from sentry_sdk.traces import StreamedSpan +from sentry_sdk.traces import ( + StreamedSpan, + SegmentSource, + SOURCE_FOR_STYLE as SEGMENT_SOURCE_FOR_STYLE, +) from sentry_sdk.tracing import ( SOURCE_FOR_STYLE, Transaction, @@ -40,6 +45,7 @@ _get_installed_modules, reraise, capture_internal_exceptions, + qualname_from_function, ) from typing import TYPE_CHECKING @@ -235,7 +241,7 @@ async def _run_app( transaction_source, "value", transaction_source ), "sentry.origin": self.span_origin, - "asgi.type": ty, + "network.protocol.name": ty, } if ty in ("http", "websocket"): @@ -302,6 +308,12 @@ async def _run_app( ) with span_ctx as span: + if isinstance(span, StreamedSpan): + for attribute, value in _get_request_attributes( + scope + ).items(): + span.set_attribute(attribute, value) + try: async def _sentry_wrapped_send( @@ -336,6 +348,7 @@ async def _sentry_wrapped_send( return await self.app( scope, receive, _sentry_wrapped_send ) + except Exception as exc: suppress_chained_exceptions = ( sentry_sdk.get_client() @@ -350,6 +363,28 @@ async def _sentry_wrapped_send( with capture_internal_exceptions(): self._capture_request_exception(exc) reraise(*exc_info) + + finally: + if isinstance(span, StreamedSpan): + already_set = ( + span is not None + and span.name != _DEFAULT_TRANSACTION_NAME + and span.get_attributes().get("sentry.span.source") + in [ + SegmentSource.COMPONENT.value, + SegmentSource.ROUTE.value, + SegmentSource.CUSTOM.value, + ] + ) + with capture_internal_exceptions(): + if not already_set: + name, source = ( + self._get_segment_name_and_source( + self.transaction_style, scope + ) + ) + span.name = name + span.set_attribute("sentry.span.source", source) finally: _asgi_middleware_applied.set(False) @@ -424,3 +459,40 @@ def _get_transaction_name_and_source( return name, source return name, source + + 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 + ty = asgi_scope.get("type") + + if segment_style == "endpoint": + endpoint = asgi_scope.get("endpoint") + # Webframeworks like Starlette mutate the ASGI env once routing is + # done, which is sometime after the request has started. If we have + # an endpoint, overwrite our generic transaction name. + if endpoint: + name = qualname_from_function(endpoint) or "" + else: + name = _get_url(asgi_scope, "http" if ty == "http" else "ws", host=None) + source = SegmentSource.URL.value + + elif segment_style == "url": + # FastAPI includes the route object in the scope to let Sentry extract the + # path from it for the transaction name + route = asgi_scope.get("route") + if route: + path = getattr(route, "path", None) + if path is not None: + name = path + else: + name = _get_url(asgi_scope, "http" if ty == "http" else "ws", host=None) + source = SegmentSource.URL.value + + if name is None: + name = _DEFAULT_TRANSACTION_NAME + source = SegmentSource.ROUTE.value + return name, source + + return name, source diff --git a/sentry_sdk/integrations/asyncio.py b/sentry_sdk/integrations/asyncio.py index b7aa0a7202..91fd54bf3a 100644 --- a/sentry_sdk/integrations/asyncio.py +++ b/sentry_sdk/integrations/asyncio.py @@ -5,7 +5,13 @@ from sentry_sdk.consts import OP from sentry_sdk.integrations import Integration, DidNotEnable from sentry_sdk.integrations._wsgi_common import nullcontext -from sentry_sdk.utils import event_from_exception, logger, reraise +from sentry_sdk.utils import ( + event_from_exception, + logger, + reraise, + is_internal_task, +) +from sentry_sdk.transport import AsyncHttpTransport try: import asyncio @@ -13,7 +19,7 @@ except ImportError: raise DidNotEnable("asyncio not available") -from typing import cast, TYPE_CHECKING +from typing import TYPE_CHECKING if TYPE_CHECKING: from typing import Any, Callable, TypeVar @@ -42,6 +48,76 @@ def _wrap_coroutine(wrapped: "Coroutine[Any, Any, Any]") -> "Callable[[T], T]": ) +def patch_loop_close() -> None: + """Patch loop.close to flush pending events before shutdown.""" + # Atexit shutdown hook happens after the event loop is closed. + # Therefore, it is necessary to patch the loop.close method to ensure + # that pending events are flushed before the interpreter shuts down. + try: + loop = asyncio.get_running_loop() + except RuntimeError: + # No running loop β†’ cannot patch now + return + + if getattr(loop, "_sentry_flush_patched", False): + return + + async def _flush() -> None: + client = sentry_sdk.get_client() + if not client.is_active(): + return + + try: + if not isinstance(client.transport, AsyncHttpTransport): + return + + await client.close_async() + except Exception: + logger.warning("Sentry flush failed during loop shutdown", exc_info=True) + + orig_close = loop.close + + def _patched_close() -> None: + try: + loop.run_until_complete(_flush()) + except Exception: + logger.debug( + "Could not flush Sentry events during loop close", exc_info=True + ) + finally: + orig_close() + + loop.close = _patched_close # type: ignore + loop._sentry_flush_patched = True # type: ignore + + +def _create_task_with_factory( + orig_task_factory: "Any", + loop: "asyncio.AbstractEventLoop", + coro: "Coroutine[Any, Any, Any]", + **kwargs: "Any", +) -> "asyncio.Task[Any]": + task = None + + # Trying to use user set task factory (if there is one) + if orig_task_factory: + task = orig_task_factory(loop, coro, **kwargs) + + if task is None: + # The default task factory in `asyncio` does not have its own function + # but is just a couple of lines in `asyncio.base_events.create_task()` + # Those lines are copied here. + + # WARNING: + # If the default behavior of the task creation in asyncio changes, + # this will break! + task = Task(coro, loop=loop, **kwargs) + if task._source_traceback: # type: ignore + del task._source_traceback[-1] # type: ignore + + return task + + def patch_asyncio() -> None: orig_task_factory = None try: @@ -57,6 +133,12 @@ def _sentry_task_factory( coro: "Coroutine[Any, Any, Any]", **kwargs: "Any", ) -> "asyncio.Future[Any]": + # Check if this is an internal Sentry task + if is_internal_task(): + return _create_task_with_factory( + orig_task_factory, loop, coro, **kwargs + ) + @_wrap_coroutine(coro) async def _task_with_sentry_span_creation() -> "Any": result = None @@ -85,31 +167,13 @@ async def _task_with_sentry_span_creation() -> "Any": return result - task = None - - # Trying to use user set task factory (if there is one) - if orig_task_factory: - task = orig_task_factory( - loop, _task_with_sentry_span_creation(), **kwargs - ) - - if task is None: - # The default task factory in `asyncio` does not have its own function - # but is just a couple of lines in `asyncio.base_events.create_task()` - # Those lines are copied here. - - # WARNING: - # If the default behavior of the task creation in asyncio changes, - # this will break! - task = Task(_task_with_sentry_span_creation(), loop=loop, **kwargs) - if task._source_traceback: # type: ignore - del task._source_traceback[-1] # type: ignore + task = _create_task_with_factory( + orig_task_factory, loop, _task_with_sentry_span_creation(), **kwargs + ) # Set the task name to include the original coroutine's name try: - cast("asyncio.Task[Any]", task).set_name( - f"{get_name(coro)} (Sentry-wrapped)" - ) + task.set_name(f"{get_name(coro)} (Sentry-wrapped)") except AttributeError: # set_name might not be available in all Python versions pass @@ -156,6 +220,7 @@ def __init__(self, task_spans: bool = True) -> None: @staticmethod def setup_once() -> None: patch_asyncio() + patch_loop_close() def enable_asyncio_integration(*args: "Any", **kwargs: "Any") -> None: diff --git a/sentry_sdk/integrations/asyncpg.py b/sentry_sdk/integrations/asyncpg.py index 7f3591154a..29f3bad152 100644 --- a/sentry_sdk/integrations/asyncpg.py +++ b/sentry_sdk/integrations/asyncpg.py @@ -1,5 +1,6 @@ from __future__ import annotations import contextlib +import re from typing import Any, TypeVar, Callable, Awaitable, Iterator import sentry_sdk @@ -55,6 +56,10 @@ def setup_once() -> None: T = TypeVar("T") +def _normalize_query(query: str) -> str: + return re.sub(r"\s+", " ", query).strip() + + def _wrap_execute(f: "Callable[..., Awaitable[T]]") -> "Callable[..., Awaitable[T]]": async def _inner(*args: "Any", **kwargs: "Any") -> "T": if sentry_sdk.get_client().get_integration(AsyncPGIntegration) is None: @@ -67,7 +72,7 @@ async def _inner(*args: "Any", **kwargs: "Any") -> "T": if len(args) > 2: return await f(*args, **kwargs) - query = args[1] + query = _normalize_query(args[1]) with record_sql_queries( cursor=None, query=query, @@ -103,6 +108,7 @@ def _record( param_style = "pyformat" if params_list else None + query = _normalize_query(query) with record_sql_queries( cursor=cursor, query=query, @@ -178,6 +184,7 @@ async def _inner(*args: "Any", **kwargs: "Any") -> "T": pass span.set_data(SPANDATA.DB_NAME, database) span.set_data(SPANDATA.DB_USER, user) + span.set_data(SPANDATA.DB_DRIVER_NAME, "asyncpg") with capture_internal_exceptions(): sentry_sdk.add_breadcrumb( @@ -192,6 +199,7 @@ async def _inner(*args: "Any", **kwargs: "Any") -> "T": def _set_db_data(span: "Span", conn: "Any") -> None: span.set_data(SPANDATA.DB_SYSTEM, "postgresql") + span.set_data(SPANDATA.DB_DRIVER_NAME, "asyncpg") addr = conn._addr if addr: diff --git a/sentry_sdk/integrations/celery/utils.py b/sentry_sdk/integrations/celery/utils.py index f9378558c1..3a526ccdfa 100644 --- a/sentry_sdk/integrations/celery/utils.py +++ b/sentry_sdk/integrations/celery/utils.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, cast if TYPE_CHECKING: - from typing import Any, Tuple + from typing import Tuple from sentry_sdk._types import MonitorConfigScheduleUnit @@ -29,11 +29,3 @@ def _get_humanized_interval(seconds: float) -> "Tuple[int, MonitorConfigSchedule return (interval, cast("MonitorConfigScheduleUnit", unit)) return (int(seconds), "second") - - -class NoOpMgr: - def __enter__(self) -> None: - return None - - def __exit__(self, exc_type: "Any", exc_value: "Any", traceback: "Any") -> None: - return None diff --git a/sentry_sdk/integrations/clickhouse_driver.py b/sentry_sdk/integrations/clickhouse_driver.py index 7bbea94210..3b7ec9891e 100644 --- a/sentry_sdk/integrations/clickhouse_driver.py +++ b/sentry_sdk/integrations/clickhouse_driver.py @@ -165,6 +165,7 @@ def wrapped_generator() -> "Iterator[Any]": def _set_db_data(span: "Span", connection: "Connection") -> None: span.set_data(SPANDATA.DB_SYSTEM, "clickhouse") + span.set_data(SPANDATA.DB_DRIVER_NAME, "clickhouse-driver") span.set_data(SPANDATA.SERVER_ADDRESS, connection.host) span.set_data(SPANDATA.SERVER_PORT, connection.port) span.set_data(SPANDATA.DB_NAME, connection.database) diff --git a/sentry_sdk/integrations/google_genai/utils.py b/sentry_sdk/integrations/google_genai/utils.py index 28b54a8bcd..25763ebe07 100644 --- a/sentry_sdk/integrations/google_genai/utils.py +++ b/sentry_sdk/integrations/google_genai/utils.py @@ -31,7 +31,7 @@ event_from_exception, safe_serialize, ) -from google.genai.types import GenerateContentConfig, Part, Content +from google.genai.types import GenerateContentConfig, Part, Content, PartDict from itertools import chain if TYPE_CHECKING: @@ -47,6 +47,18 @@ ContentUnion, ) +_is_PIL_available = False +try: + from PIL import Image as PILImage # type: ignore[import-not-found] + + _is_PIL_available = True +except ImportError: + pass + +# Keys to use when checking to see if a dict provided by the user +# is Part-like (as opposed to a Content or multi-turn conversation entry). +_PART_DICT_KEYS = PartDict.__optional_keys__ + class UsageData(TypedDict): """Structure for token usage data.""" @@ -169,12 +181,23 @@ def extract_contents_messages(contents: "ContentListUnion") -> "List[Dict[str, A if isinstance(contents, str): return [{"role": "user", "content": contents}] - # Handle list case - process each item (non-recursive, flatten at top level) + # Handle list case if isinstance(contents, list): - for item in contents: - item_messages = extract_contents_messages(item) - messages.extend(item_messages) - return messages + if contents and all(_is_part_like(item) for item in contents): + # All items are parts β€” merge into a single multi-part user message + content_parts = [] + for item in contents: + part = _extract_part_from_item(item) + if part is not None: + content_parts.append(part) + + return [{"role": "user", "content": content_parts}] + else: + # Multi-turn conversation or mixed content types + for item in contents: + item_messages = extract_contents_messages(item) + messages.extend(item_messages) + return messages # Handle dictionary case (ContentDict) if isinstance(contents, dict): @@ -206,13 +229,23 @@ def extract_contents_messages(contents: "ContentListUnion") -> "List[Dict[str, A # Add tool messages messages.extend(tool_messages) elif "text" in contents: - # Simple text in dict messages.append( { - "role": role or "user", + "role": role, "content": [{"text": contents["text"], "type": "text"}], } ) + elif "inline_data" in contents: + # The "data" will always be bytes (or bytes within a string), + # so if this is present, it's safe to automatically substitute with the placeholder + messages.append( + { + "inline_data": { + "mime_type": contents["inline_data"].get("mime_type", ""), + "data": BLOB_DATA_SUBSTITUTE, + } + } + ) return messages @@ -248,15 +281,10 @@ def extract_contents_messages(contents: "ContentListUnion") -> "List[Dict[str, A return [{"role": "user", "content": [part_result]}] # Handle PIL.Image.Image - try: - from PIL import Image as PILImage # type: ignore[import-not-found] - - if isinstance(contents, PILImage.Image): - blob_part = _extract_pil_image(contents) - if blob_part: - return [{"role": "user", "content": [blob_part]}] - except ImportError: - pass + if _is_PIL_available and isinstance(contents, PILImage.Image): + blob_part = _extract_pil_image(contents) + if blob_part: + return [{"role": "user", "content": [blob_part]}] # Handle File object if hasattr(contents, "uri") and hasattr(contents, "mime_type"): @@ -310,11 +338,9 @@ def _extract_part_content(part: "Any") -> "Optional[dict[str, Any]]": if result is not None: # For inline_data with bytes data, substitute the content if "inline_data" in part: - inline_data = part["inline_data"] - if isinstance(inline_data, dict) and isinstance( - inline_data.get("data"), bytes - ): - result["content"] = BLOB_DATA_SUBSTITUTE + # inline_data.data will always be bytes, or a string containing base64-encoded bytes, + # so can automatically substitute without further checks + result["content"] = BLOB_DATA_SUBSTITUTE return result return None @@ -357,18 +383,11 @@ def _extract_part_content(part: "Any") -> "Optional[dict[str, Any]]": if mime_type is None: mime_type = "" - # Handle both bytes (binary data) and str (base64-encoded data) - if isinstance(data, bytes): - content = BLOB_DATA_SUBSTITUTE - else: - # For non-bytes data (e.g., base64 strings), use as-is - content = data - return { "type": "blob", "modality": get_modality_from_mime_type(mime_type), "mime_type": mime_type, - "content": content, + "content": BLOB_DATA_SUBSTITUTE, } return None @@ -429,25 +448,78 @@ def _extract_tool_message_from_part(part: "Any") -> "Optional[dict[str, Any]]": def _extract_pil_image(image: "Any") -> "Optional[dict[str, Any]]": """Extract blob part from PIL.Image.Image.""" - try: - from PIL import Image as PILImage + if not _is_PIL_available or not isinstance(image, PILImage.Image): + return None + + # Get format, default to JPEG + format_str = image.format or "JPEG" + suffix = format_str.lower() + mime_type = f"image/{suffix}" - if not isinstance(image, PILImage.Image): - return None + return { + "type": "blob", + "modality": get_modality_from_mime_type(mime_type), + "mime_type": mime_type, + "content": BLOB_DATA_SUBSTITUTE, + } - # Get format, default to JPEG - format_str = image.format or "JPEG" - suffix = format_str.lower() - mime_type = f"image/{suffix}" +def _is_part_like(item: "Any") -> bool: + """Check if item is a part-like value (PartUnionDict) rather than a Content/multi-turn entry.""" + if isinstance(item, (str, Part)): + return True + if isinstance(item, (list, Content)): + return False + if isinstance(item, dict): + if "role" in item or "parts" in item: + return False + # Part objects that came in as plain dicts + return bool(_PART_DICT_KEYS & item.keys()) + # File objects + if hasattr(item, "uri"): + return True + # PIL.Image + if _is_PIL_available and isinstance(item, PILImage.Image): + return True + return False + + +def _extract_part_from_item(item: "Any") -> "Optional[dict[str, Any]]": + """Convert a single part-like item to a content part dict.""" + if isinstance(item, str): + return {"text": item, "type": "text"} + + # Handle bare inline_data dicts directly to preserve the raw format + if isinstance(item, dict) and "inline_data" in item: return { - "type": "blob", - "modality": get_modality_from_mime_type(mime_type), - "mime_type": mime_type, - "content": BLOB_DATA_SUBSTITUTE, + "inline_data": { + "mime_type": item["inline_data"].get("mime_type", ""), + "data": BLOB_DATA_SUBSTITUTE, + } } - except Exception: - return None + + # For other dicts and Part objects, use existing _extract_part_content + result = _extract_part_content(item) + if result is not None: + return result + + # PIL.Image + if _is_PIL_available and isinstance(item, PILImage.Image): + return _extract_pil_image(item) + + # File objects + if hasattr(item, "uri") and hasattr(item, "mime_type"): + file_uri = getattr(item, "uri", None) + mime_type = getattr(item, "mime_type", None) or "" + if file_uri is not None: + return { + "type": "uri", + "modality": get_modality_from_mime_type(mime_type), + "mime_type": mime_type, + "uri": file_uri, + } + + return None def extract_contents_text(contents: "ContentListUnion") -> "Optional[str]": @@ -597,7 +669,6 @@ def _create_tool_span(tool_name: str, tool_doc: "Optional[str]") -> "Span": origin=ORIGIN, ) span.set_data(SPANDATA.GEN_AI_TOOL_NAME, tool_name) - span.set_data(SPANDATA.GEN_AI_TOOL_TYPE, "function") if tool_doc: span.set_data(SPANDATA.GEN_AI_TOOL_DESCRIPTION, tool_doc) return span @@ -696,6 +767,9 @@ def _extract_response_text( if not hasattr(candidate, "content") or not hasattr(candidate.content, "parts"): continue + if candidate.content is None or candidate.content.parts is None: + continue + for part in candidate.content.parts: if getattr(part, "text", None): texts.append(part.text) diff --git a/sentry_sdk/integrations/grpc/aio/server.py b/sentry_sdk/integrations/grpc/aio/server.py index 1e9eac8920..084c76ecc0 100644 --- a/sentry_sdk/integrations/grpc/aio/server.py +++ b/sentry_sdk/integrations/grpc/aio/server.py @@ -43,31 +43,32 @@ async def intercept_service( handler_factory = grpc.unary_unary_rpc_method_handler async def wrapped(request: "Any", context: "ServicerContext") -> "Any": - name = self._find_method_name(context) - if not name: - return await handler(request, context) - - # 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 + with sentry_sdk.isolation_scope(): + name = self._find_method_name(context) + if not name: + return await handler(request, context) + + # 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 elif not handler.request_streaming and handler.response_streaming: handler_factory = grpc.unary_stream_rpc_method_handler diff --git a/sentry_sdk/integrations/huggingface_hub.py b/sentry_sdk/integrations/huggingface_hub.py index 8509cadefa..d628ccf546 100644 --- a/sentry_sdk/integrations/huggingface_hub.py +++ b/sentry_sdk/integrations/huggingface_hub.py @@ -1,6 +1,7 @@ -import sys import inspect +import sys from functools import wraps +from typing import TYPE_CHECKING import sentry_sdk from sentry_sdk.ai.monitoring import record_token_usage @@ -8,15 +9,12 @@ 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 set_span_errored from sentry_sdk.utils import ( capture_internal_exceptions, event_from_exception, reraise, ) -from typing import TYPE_CHECKING - if TYPE_CHECKING: from typing import Any, Callable, Iterable @@ -41,7 +39,7 @@ def setup_once() -> None: huggingface_hub.inference._client.InferenceClient.text_generation = ( _wrap_huggingface_task( huggingface_hub.inference._client.InferenceClient.text_generation, - OP.GEN_AI_GENERATE_TEXT, + OP.GEN_AI_TEXT_COMPLETION, ) ) huggingface_hub.inference._client.InferenceClient.chat_completion = ( @@ -53,8 +51,6 @@ def setup_once() -> None: def _capture_exception(exc: "Any") -> None: - set_span_errored() - event, hint = event_from_exception( exc, client_options=sentry_sdk.get_client().options, @@ -131,7 +127,7 @@ def new_huggingface_task(*args: "Any", **kwargs: "Any") -> "Any": exc_info = sys.exc_info() with capture_internal_exceptions(): _capture_exception(e) - span.__exit__(None, None, None) + span.__exit__(*exc_info) reraise(*exc_info) # Output attributes diff --git a/sentry_sdk/integrations/langchain.py b/sentry_sdk/integrations/langchain.py index d19d9bbdd5..49fa04c034 100644 --- a/sentry_sdk/integrations/langchain.py +++ b/sentry_sdk/integrations/langchain.py @@ -108,6 +108,15 @@ OllamaEmbeddings = None +def _get_ai_system(all_params: "Dict[str, Any]") -> "Optional[str]": + ai_type = all_params.get("_type") + + if not ai_type or not isinstance(ai_type, str): + return None + + return ai_type + + DATA_FIELDS = { "frequency_penalty": SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY, "function_call": SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS, @@ -351,7 +360,6 @@ def on_llm_start( metadata: "Optional[Dict[str, Any]]" = None, **kwargs: "Any", ) -> "Any": - """Run when LLM starts running.""" with capture_internal_exceptions(): if not run_id: return @@ -369,23 +377,27 @@ def on_llm_start( watched_span = self._create_span( run_id, parent_run_id, - op=OP.GEN_AI_PIPELINE, - name=kwargs.get("name") or "Langchain LLM call", + op=OP.GEN_AI_TEXT_COMPLETION, + name=f"text_completion {model}".strip(), origin=LangchainIntegration.origin, ) span = watched_span.span + span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "text_completion") + + pipeline_name = kwargs.get("name") + if pipeline_name: + span.set_data(SPANDATA.GEN_AI_PIPELINE_NAME, pipeline_name) + if model: span.set_data( SPANDATA.GEN_AI_REQUEST_MODEL, model, ) - ai_type = all_params.get("_type", "") - if "anthropic" in ai_type: - span.set_data(SPANDATA.GEN_AI_SYSTEM, "anthropic") - elif "openai" in ai_type: - span.set_data(SPANDATA.GEN_AI_SYSTEM, "openai") + ai_system = _get_ai_system(all_params) + if ai_system: + span.set_data(SPANDATA.GEN_AI_SYSTEM, ai_system) for key, attribute in DATA_FIELDS.items(): if key in all_params and all_params[key] is not None: @@ -449,11 +461,9 @@ def on_chat_model_start( if model: span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model) - ai_type = all_params.get("_type", "") - if "anthropic" in ai_type: - span.set_data(SPANDATA.GEN_AI_SYSTEM, "anthropic") - elif "openai" in ai_type: - span.set_data(SPANDATA.GEN_AI_SYSTEM, "openai") + ai_system = _get_ai_system(all_params) + if ai_system: + span.set_data(SPANDATA.GEN_AI_SYSTEM, ai_system) agent_name = _get_current_agent() if agent_name: diff --git a/sentry_sdk/integrations/litellm.py b/sentry_sdk/integrations/litellm.py index 28bcc34d3e..3cff0fbc23 100644 --- a/sentry_sdk/integrations/litellm.py +++ b/sentry_sdk/integrations/litellm.py @@ -82,7 +82,7 @@ def _input_callback(kwargs: "Dict[str, Any]") -> None: provider = "unknown" call_type = kwargs.get("call_type", None) - if call_type == "embedding": + if call_type == "embedding" or call_type == "aembedding": operation = "embeddings" else: operation = "chat" @@ -159,15 +159,9 @@ def _input_callback(kwargs: "Dict[str, Any]") -> None: if value is not None: set_data_normalized(span, attribute, value) - # Record LiteLLM-specific parameters - litellm_params = { - "api_base": kwargs.get("api_base"), - "api_version": kwargs.get("api_version"), - "custom_llm_provider": kwargs.get("custom_llm_provider"), - } - for key, value in litellm_params.items(): - if value is not None: - set_data_normalized(span, f"gen_ai.litellm.{key}", value) + +async def _async_input_callback(kwargs: "Dict[str, Any]") -> None: + return _input_callback(kwargs) def _success_callback( @@ -178,7 +172,8 @@ def _success_callback( ) -> None: """Handle successful completion.""" - span = _get_metadata_dict(kwargs).get("_sentry_span") + metadata = _get_metadata_dict(kwargs) + span = metadata.get("_sentry_span") if span is None: return @@ -230,8 +225,31 @@ def _success_callback( ) finally: - # Always finish the span and clean up - span.__exit__(None, None, None) + is_streaming = kwargs.get("stream") + # Callback is fired multiple times when streaming a response. + # Streaming flag checked at https://github.com/BerriAI/litellm/blob/33c3f13443eaf990ac8c6e3da78bddbc2b7d0e7a/litellm/litellm_core_utils/litellm_logging.py#L1603 + if ( + is_streaming is not True + or "complete_streaming_response" in kwargs + or "async_complete_streaming_response" in kwargs + ): + span = metadata.pop("_sentry_span", None) + if span is not None: + span.__exit__(None, None, None) + + +async def _async_success_callback( + kwargs: "Dict[str, Any]", + completion_response: "Any", + start_time: "datetime", + end_time: "datetime", +) -> None: + return _success_callback( + kwargs, + completion_response, + start_time, + end_time, + ) def _failure_callback( @@ -315,10 +333,14 @@ def setup_once() -> None: litellm.input_callback = input_callback or [] if _input_callback not in litellm.input_callback: litellm.input_callback.append(_input_callback) + if _async_input_callback not in litellm.input_callback: + litellm.input_callback.append(_async_input_callback) litellm.success_callback = success_callback or [] if _success_callback not in litellm.success_callback: litellm.success_callback.append(_success_callback) + if _async_success_callback not in litellm.success_callback: + litellm.success_callback.append(_async_success_callback) litellm.failure_callback = failure_callback or [] if _failure_callback not in litellm.failure_callback: diff --git a/sentry_sdk/integrations/openai.py b/sentry_sdk/integrations/openai.py index a5556b8776..480db9132d 100644 --- a/sentry_sdk/integrations/openai.py +++ b/sentry_sdk/integrations/openai.py @@ -50,7 +50,13 @@ from sentry_sdk.tracing import Span from sentry_sdk._types import TextPart - from openai.types.responses import ResponseInputParam, SequenceNotStr + from openai.types.responses.response_usage import ResponseUsage + from openai.types.responses import ( + ResponseInputParam, + SequenceNotStr, + ResponseStreamEvent, + ) + from openai.types import CompletionUsage from openai import Omit try: @@ -67,6 +73,8 @@ from openai.resources.chat.completions import Completions, AsyncCompletions from openai.resources import Embeddings, AsyncEmbeddings + from openai import Stream, AsyncStream + if TYPE_CHECKING: from openai.types.chat import ( ChatCompletionMessageParam, @@ -141,44 +149,56 @@ def _capture_exception(exc: "Any", manual_span_cleanup: bool = True) -> None: sentry_sdk.capture_event(event, hint=hint) -def _get_usage(usage: "Any", names: "List[str]") -> int: - for name in names: - if hasattr(usage, name) and isinstance(getattr(usage, name), int): - return getattr(usage, name) - return 0 +def _has_attr_and_is_int( + token_usage: "Union[CompletionUsage, ResponseUsage]", attr_name: str +) -> bool: + return hasattr(token_usage, attr_name) and isinstance( + getattr(token_usage, attr_name, None), int + ) -def _calculate_token_usage( +def _calculate_completions_token_usage( messages: "Optional[Iterable[ChatCompletionMessageParam]]", response: "Any", span: "Span", streaming_message_responses: "Optional[List[str]]", + streaming_message_total_token_usage: "Optional[CompletionUsage]", count_tokens: "Callable[..., Any]", ) -> None: + """Extract and record token usage from a Chat Completions API response.""" input_tokens: "Optional[int]" = 0 input_tokens_cached: "Optional[int]" = 0 output_tokens: "Optional[int]" = 0 output_tokens_reasoning: "Optional[int]" = 0 total_tokens: "Optional[int]" = 0 - - if hasattr(response, "usage"): - input_tokens = _get_usage(response.usage, ["input_tokens", "prompt_tokens"]) - if hasattr(response.usage, "input_tokens_details"): - input_tokens_cached = _get_usage( - response.usage.input_tokens_details, ["cached_tokens"] - ) - - output_tokens = _get_usage( - response.usage, ["output_tokens", "completion_tokens"] - ) - if hasattr(response.usage, "output_tokens_details"): - output_tokens_reasoning = _get_usage( - response.usage.output_tokens_details, ["reasoning_tokens"] + usage = None + + if streaming_message_total_token_usage is not None: + usage = streaming_message_total_token_usage + elif hasattr(response, "usage"): + usage = response.usage + + if usage is not None: + if _has_attr_and_is_int(usage, "prompt_tokens"): + input_tokens = usage.prompt_tokens + if _has_attr_and_is_int(usage, "completion_tokens"): + output_tokens = usage.completion_tokens + if _has_attr_and_is_int(usage, "total_tokens"): + total_tokens = usage.total_tokens + + if hasattr(usage, "prompt_tokens_details"): + cached = getattr(usage.prompt_tokens_details, "cached_tokens", None) + if isinstance(cached, int): + input_tokens_cached = cached + + if hasattr(usage, "completion_tokens_details"): + reasoning = getattr( + usage.completion_tokens_details, "reasoning_tokens", None ) + if isinstance(reasoning, int): + output_tokens_reasoning = reasoning - total_tokens = _get_usage(response.usage, ["total_tokens"]) - - # Manually count tokens + # Manually count input tokens if input_tokens == 0: for message in messages or []: if isinstance(message, str): @@ -188,11 +208,11 @@ def _calculate_token_usage( message_content = message.get("content") if message_content is None: continue - # Deliberate use of Completions function for both Completions and Responses input format. text_items = _get_text_items(message_content) input_tokens += sum(count_tokens(text) for text in text_items) continue + # Manually count output tokens if output_tokens == 0: if streaming_message_responses is not None: for message in streaming_message_responses: @@ -219,35 +239,82 @@ def _calculate_token_usage( ) -def _commmon_set_input_data( +def _calculate_responses_token_usage( + input: "Any", + response: "Any", span: "Span", - kwargs: "dict[str, Any]", + streaming_message_responses: "Optional[List[str]]", + count_tokens: "Callable[..., Any]", ) -> None: - # Input attributes: Common - set_data_normalized(span, SPANDATA.GEN_AI_SYSTEM, "openai") - - # Input attributes: Optional - kwargs_keys_to_attributes = { - "model": SPANDATA.GEN_AI_REQUEST_MODEL, - "stream": SPANDATA.GEN_AI_RESPONSE_STREAMING, - "max_tokens": SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, - "presence_penalty": SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY, - "frequency_penalty": SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY, - "temperature": SPANDATA.GEN_AI_REQUEST_TEMPERATURE, - "top_p": SPANDATA.GEN_AI_REQUEST_TOP_P, - } - for key, attribute in kwargs_keys_to_attributes.items(): - value = kwargs.get(key) - - if value is not None and _is_given(value): - set_data_normalized(span, attribute, value) - - # Input attributes: Tools - tools = kwargs.get("tools") - if tools is not None and _is_given(tools) and len(tools) > 0: - set_data_normalized( - span, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools) - ) + """Extract and record token usage from a Responses API response.""" + input_tokens: "Optional[int]" = 0 + input_tokens_cached: "Optional[int]" = 0 + output_tokens: "Optional[int]" = 0 + output_tokens_reasoning: "Optional[int]" = 0 + total_tokens: "Optional[int]" = 0 + + if hasattr(response, "usage"): + usage = response.usage + + if _has_attr_and_is_int(usage, "input_tokens"): + input_tokens = usage.input_tokens + if _has_attr_and_is_int(usage, "output_tokens"): + output_tokens = usage.output_tokens + if _has_attr_and_is_int(usage, "total_tokens"): + total_tokens = usage.total_tokens + + if hasattr(usage, "input_tokens_details"): + cached = getattr(usage.input_tokens_details, "cached_tokens", None) + if isinstance(cached, int): + input_tokens_cached = cached + + if hasattr(usage, "output_tokens_details"): + reasoning = getattr(usage.output_tokens_details, "reasoning_tokens", None) + if isinstance(reasoning, int): + output_tokens_reasoning = reasoning + + # Manually count input tokens + if input_tokens == 0: + for message in input or []: + if isinstance(message, str): + input_tokens += count_tokens(message) + continue + elif isinstance(message, dict): + message_content = message.get("content") + if message_content is None: + continue + # Deliberate use of Completions function for both Completions and Responses input format. + text_items = _get_text_items(message_content) + input_tokens += sum(count_tokens(text) for text in text_items) + continue + + # Manually count output tokens + if output_tokens == 0: + if streaming_message_responses is not None: + for message in streaming_message_responses: + output_tokens += count_tokens(message) + elif hasattr(response, "output"): + for output_item in response.output: + if hasattr(output_item, "content"): + for content_item in output_item.content: + if hasattr(content_item, "text"): + output_tokens += count_tokens(content_item.text) + + # Do not set token data if it is 0 + input_tokens = input_tokens or None + input_tokens_cached = input_tokens_cached or None + output_tokens = output_tokens or None + output_tokens_reasoning = output_tokens_reasoning or None + total_tokens = total_tokens or None + + record_token_usage( + span, + input_tokens=input_tokens, + input_tokens_cached=input_tokens_cached, + output_tokens=output_tokens, + output_tokens_reasoning=output_tokens_reasoning, + total_tokens=total_tokens, + ) def _set_responses_api_input_data( @@ -258,9 +325,30 @@ def _set_responses_api_input_data( explicit_instructions: "Union[Optional[str], Omit]" = kwargs.get("instructions") messages: "Optional[Union[str, ResponseInputParam]]" = kwargs.get("input") + tools = kwargs.get("tools") + if tools is not None and _is_given(tools) and len(tools) > 0: + set_data_normalized( + span, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools) + ) + + model = kwargs.get("model") + if model is not None: + span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model) + + max_tokens = kwargs.get("max_output_tokens") + if max_tokens is not None and _is_given(max_tokens): + span.set_data(SPANDATA.GEN_AI_REQUEST_MAX_TOKENS, max_tokens) + + temperature = kwargs.get("temperature") + if temperature is not None and _is_given(temperature): + span.set_data(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature) + + top_p = kwargs.get("top_p") + if top_p is not None and _is_given(top_p): + span.set_data(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p) + if not should_send_default_pii() or not integration.include_prompts: set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "responses") - _commmon_set_input_data(span, kwargs) return if ( @@ -281,12 +369,10 @@ def _set_responses_api_input_data( ) set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "responses") - _commmon_set_input_data(span, kwargs) return if messages is None: set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "responses") - _commmon_set_input_data(span, kwargs) return instructions_text_parts: "list[TextPart]" = [] @@ -319,7 +405,6 @@ def _set_responses_api_input_data( ) set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "responses") - _commmon_set_input_data(span, kwargs) return non_system_messages = [ @@ -335,7 +420,6 @@ def _set_responses_api_input_data( ) set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "responses") - _commmon_set_input_data(span, kwargs) def _set_completions_api_input_data( @@ -347,13 +431,42 @@ def _set_completions_api_input_data( "messages" ) + tools = kwargs.get("tools") + if tools is not None and _is_given(tools) and len(tools) > 0: + set_data_normalized( + span, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, safe_serialize(tools) + ) + + model = kwargs.get("model") + if model is not None: + span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model) + + max_tokens = kwargs.get("max_tokens") + if max_tokens is not None and _is_given(max_tokens): + span.set_data(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): + span.set_data(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): + span.set_data(SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY, frequency_penalty) + + temperature = kwargs.get("temperature") + if temperature is not None and _is_given(temperature): + span.set_data(SPANDATA.GEN_AI_REQUEST_TEMPERATURE, temperature) + + top_p = kwargs.get("top_p") + if top_p is not None and _is_given(top_p): + span.set_data(SPANDATA.GEN_AI_REQUEST_TOP_P, top_p) + if ( not should_send_default_pii() or not integration.include_prompts or messages is None ): set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "chat") - _commmon_set_input_data(span, kwargs) return if isinstance(messages, str): @@ -365,13 +478,11 @@ def _set_completions_api_input_data( span, SPANDATA.GEN_AI_REQUEST_MESSAGES, messages_data, unpack=False ) set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "chat") - _commmon_set_input_data(span, kwargs) return # dict special case following https://github.com/openai/openai-python/blob/3e0c05b84a2056870abf3bd6a5e7849020209cc3/src/openai/_utils/_transform.py#L194-L197 if not isinstance(messages, Iterable) or isinstance(messages, dict): set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "chat") - _commmon_set_input_data(span, kwargs) return messages = list(messages) @@ -399,7 +510,6 @@ def _set_completions_api_input_data( ) set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "chat") - _commmon_set_input_data(span, kwargs) def _set_embeddings_input_data( @@ -411,19 +521,21 @@ def _set_embeddings_input_data( "input" ) + model = kwargs.get("model") + if model is not None: + span.set_data(SPANDATA.GEN_AI_REQUEST_MODEL, model) + if ( not should_send_default_pii() or not integration.include_prompts or messages is None ): set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "embeddings") - _commmon_set_input_data(span, kwargs) return if isinstance(messages, str): set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "embeddings") - _commmon_set_input_data(span, kwargs) normalized_messages = normalize_message_roles([messages]) # type: ignore scope = sentry_sdk.get_current_scope() @@ -440,7 +552,6 @@ def _set_embeddings_input_data( # dict special case following https://github.com/openai/openai-python/blob/3e0c05b84a2056870abf3bd6a5e7849020209cc3/src/openai/_utils/_transform.py#L194-L197 if not isinstance(messages, Iterable) or isinstance(messages, dict): set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "embeddings") - _commmon_set_input_data(span, kwargs) return messages = list(messages) @@ -458,7 +569,6 @@ def _set_embeddings_input_data( ) set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "embeddings") - _commmon_set_input_data(span, kwargs) def _set_common_output_data( @@ -471,6 +581,7 @@ def _set_common_output_data( if hasattr(response, "model"): set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_MODEL, response.model) + # Chat Completions API if hasattr(response, "choices"): if should_send_default_pii() and integration.include_prompts: response_text = [ @@ -481,11 +592,19 @@ def _set_common_output_data( if len(response_text) > 0: set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, response_text) - _calculate_token_usage(input, response, span, None, integration.count_tokens) + _calculate_completions_token_usage( + messages=input, + response=response, + span=span, + streaming_message_responses=None, + streaming_message_total_token_usage=None, + count_tokens=integration.count_tokens, + ) if finish_span: span.__exit__(None, None, None) + # Responses API elif hasattr(response, "output"): if should_send_default_pii() and integration.include_prompts: output_messages: "dict[str, list[Any]]" = { @@ -517,12 +636,26 @@ def _set_common_output_data( span, SPANDATA.GEN_AI_RESPONSE_TEXT, output_messages["response"] ) - _calculate_token_usage(input, response, span, None, integration.count_tokens) + _calculate_responses_token_usage( + input=input, + response=response, + span=span, + streaming_message_responses=None, + count_tokens=integration.count_tokens, + ) if finish_span: span.__exit__(None, None, None) + # Embeddings API (fallback for responses with neither choices nor output) else: - _calculate_token_usage(input, response, span, None, integration.count_tokens) + _calculate_completions_token_usage( + messages=input, + response=response, + span=span, + streaming_message_responses=None, + streaming_message_total_token_usage=None, + count_tokens=integration.count_tokens, + ) if finish_span: span.__exit__(None, None, None) @@ -551,15 +684,49 @@ def _new_chat_completion_common(f: "Any", *args: "Any", **kwargs: "Any") -> "Any ) span.__enter__() + span.set_data(SPANDATA.GEN_AI_SYSTEM, "openai") + + # 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 + span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, is_streaming_response) + _set_completions_api_input_data(span, kwargs, integration) start_time = time.perf_counter() response = yield f, args, kwargs - is_streaming_response = kwargs.get("stream", False) - if is_streaming_response: - _set_streaming_completions_api_output_data( - span, response, kwargs, integration, start_time, finish_span=True + # Attribute check to fail gracefully if the attribute is not present in future `openai` versions. + if isinstance(response, Stream) and hasattr(response, "_iterator"): + messages = kwargs.get("messages") + + if messages is not None and isinstance(messages, str): + messages = [messages] + + response._iterator = _wrap_synchronous_completions_chunk_iterator( + span=span, + integration=integration, + start_time=start_time, + messages=messages, + response=response, + old_iterator=response._iterator, + finish_span=True, + ) + + # Attribute check to fail gracefully if the attribute is not present in future `openai` versions. + elif isinstance(response, AsyncStream) and hasattr(response, "_iterator"): + messages = kwargs.get("messages") + + if messages is not None and isinstance(messages, str): + messages = [messages] + + response._iterator = _wrap_asynchronous_completions_chunk_iterator( + span=span, + integration=integration, + start_time=start_time, + messages=messages, + response=response, + old_iterator=response._iterator, + finish_span=True, ) else: _set_completions_api_output_data( @@ -590,116 +757,254 @@ def _set_completions_api_output_data( ) -def _set_streaming_completions_api_output_data( +def _wrap_synchronous_completions_chunk_iterator( span: "Span", - response: "Any", - kwargs: "dict[str, Any]", integration: "OpenAIIntegration", - start_time: "Optional[float]" = None, - finish_span: bool = True, -) -> None: - messages = kwargs.get("messages") + start_time: "Optional[float]", + messages: "Optional[Iterable[ChatCompletionMessageParam]]", + response: "Stream[ChatCompletionChunk]", + old_iterator: "Iterator[ChatCompletionChunk]", + finish_span: "bool", +) -> "Iterator[ChatCompletionChunk]": + """ + Sets information received while iterating the response stream on the AI Client Span. + Compute token count based on inputs and outputs using tiktoken if token counts are not in the model response. + Responsible for closing the AI Client Span if instructed to by the `finish_span` argument. + """ + ttft = None + data_buf: "list[list[str]]" = [] # one for each choice + streaming_message_total_token_usage = None - if messages is not None and isinstance(messages, str): - messages = [messages] + for x in old_iterator: + span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, x.model) - ttft: "Optional[float]" = None + with capture_internal_exceptions(): + if hasattr(x, "choices"): + choice_index = 0 + for choice in x.choices: + if hasattr(choice, "delta") and hasattr(choice.delta, "content"): + if start_time is not None and ttft is None: + ttft = time.perf_counter() - start_time + content = choice.delta.content + if len(data_buf) <= choice_index: + data_buf.append([]) + data_buf[choice_index].append(content or "") + choice_index += 1 + if hasattr(x, "usage"): + streaming_message_total_token_usage = x.usage + + yield x + + with capture_internal_exceptions(): + if ttft is not None: + set_data_normalized( + span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, ttft + ) + all_responses = None + if len(data_buf) > 0: + all_responses = ["".join(chunk) for chunk in data_buf] + if should_send_default_pii() and integration.include_prompts: + set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses) + + _calculate_completions_token_usage( + messages=messages, + response=response, + span=span, + streaming_message_responses=all_responses, + streaming_message_total_token_usage=streaming_message_total_token_usage, + count_tokens=integration.count_tokens, + ) + + if finish_span: + span.__exit__(None, None, None) + + +async def _wrap_asynchronous_completions_chunk_iterator( + span: "Span", + integration: "OpenAIIntegration", + start_time: "Optional[float]", + messages: "Optional[Iterable[ChatCompletionMessageParam]]", + response: "AsyncStream[ChatCompletionChunk]", + old_iterator: "AsyncIterator[ChatCompletionChunk]", + finish_span: "bool", +) -> "AsyncIterator[ChatCompletionChunk]": + """ + Sets information received while iterating the response stream on the AI Client Span. + Compute token count based on inputs and outputs using tiktoken if token counts are not in the model response. + Responsible for closing the AI Client Span if instructed to by the `finish_span` argument. + """ + ttft = None data_buf: "list[list[str]]" = [] # one for each choice + streaming_message_total_token_usage = None - old_iterator = response._iterator - - def new_iterator() -> "Iterator[ChatCompletionChunk]": - nonlocal ttft - for x in old_iterator: - span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, x.model) - - with capture_internal_exceptions(): - if hasattr(x, "choices"): - choice_index = 0 - for choice in x.choices: - if hasattr(choice, "delta") and hasattr( - choice.delta, "content" - ): - if start_time is not None and ttft is None: - ttft = time.perf_counter() - start_time - content = choice.delta.content - if len(data_buf) <= choice_index: - data_buf.append([]) - data_buf[choice_index].append(content or "") - choice_index += 1 - - yield x + async for x in old_iterator: + span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, x.model) with capture_internal_exceptions(): - if ttft is not None: - set_data_normalized( - span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, ttft + if hasattr(x, "choices"): + choice_index = 0 + for choice in x.choices: + if hasattr(choice, "delta") and hasattr(choice.delta, "content"): + if start_time is not None and ttft is None: + ttft = time.perf_counter() - start_time + content = choice.delta.content + if len(data_buf) <= choice_index: + data_buf.append([]) + data_buf[choice_index].append(content or "") + choice_index += 1 + if hasattr(x, "usage"): + streaming_message_total_token_usage = x.usage + + yield x + + with capture_internal_exceptions(): + if ttft is not None: + set_data_normalized( + span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, ttft + ) + all_responses = None + if len(data_buf) > 0: + all_responses = ["".join(chunk) for chunk in data_buf] + if should_send_default_pii() and integration.include_prompts: + set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses) + + _calculate_completions_token_usage( + messages=messages, + response=response, + span=span, + streaming_message_responses=all_responses, + streaming_message_total_token_usage=streaming_message_total_token_usage, + count_tokens=integration.count_tokens, + ) + + if finish_span: + span.__exit__(None, None, None) + + +def _wrap_synchronous_responses_event_iterator( + span: "Span", + integration: "OpenAIIntegration", + start_time: "Optional[float]", + input: "Optional[Union[str, ResponseInputParam]]", + response: "Stream[ResponseStreamEvent]", + old_iterator: "Iterator[ResponseStreamEvent]", + finish_span: "bool", +) -> "Iterator[ResponseStreamEvent]": + """ + Sets information received while iterating the response stream on the AI Client Span. + Compute token count based on inputs and outputs using tiktoken if token counts are not in the model response. + Responsible for closing the AI Client Span if instructed to by the `finish_span` argument. + """ + ttft = None + data_buf: "list[list[str]]" = [] # one for each choice + + count_tokens_manually = True + for x in old_iterator: + with capture_internal_exceptions(): + if hasattr(x, "delta"): + if start_time is not None and ttft is None: + ttft = time.perf_counter() - start_time + if len(data_buf) == 0: + data_buf.append([]) + data_buf[0].append(x.delta or "") + + if isinstance(x, ResponseCompletedEvent): + span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, x.response.model) + + _calculate_responses_token_usage( + input=input, + response=x.response, + span=span, + streaming_message_responses=None, + count_tokens=integration.count_tokens, ) - if len(data_buf) > 0: - all_responses = ["".join(chunk) for chunk in data_buf] - if should_send_default_pii() and integration.include_prompts: - set_data_normalized( - span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses - ) - _calculate_token_usage( - messages, - response, - span, - all_responses, - integration.count_tokens, + count_tokens_manually = False + + yield x + + with capture_internal_exceptions(): + if ttft is not None: + set_data_normalized( + span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, ttft + ) + if len(data_buf) > 0: + all_responses = ["".join(chunk) for chunk in data_buf] + if should_send_default_pii() and integration.include_prompts: + set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses) + + if count_tokens_manually: + _calculate_responses_token_usage( + input=input, + response=response, + span=span, + streaming_message_responses=all_responses, + count_tokens=integration.count_tokens, ) - if finish_span: - span.__exit__(None, None, None) + if finish_span: + span.__exit__(None, None, None) - async def new_iterator_async() -> "AsyncIterator[ChatCompletionChunk]": - nonlocal ttft - async for x in old_iterator: - span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, x.model) - - with capture_internal_exceptions(): - if hasattr(x, "choices"): - choice_index = 0 - for choice in x.choices: - if hasattr(choice, "delta") and hasattr( - choice.delta, "content" - ): - if start_time is not None and ttft is None: - ttft = time.perf_counter() - start_time - content = choice.delta.content - if len(data_buf) <= choice_index: - data_buf.append([]) - data_buf[choice_index].append(content or "") - choice_index += 1 - - yield x +async def _wrap_asynchronous_responses_event_iterator( + span: "Span", + integration: "OpenAIIntegration", + start_time: "Optional[float]", + input: "Optional[Union[str, ResponseInputParam]]", + response: "AsyncStream[ResponseStreamEvent]", + old_iterator: "AsyncIterator[ResponseStreamEvent]", + finish_span: "bool", +) -> "AsyncIterator[ResponseStreamEvent]": + """ + Sets information received while iterating the response stream on the AI Client Span. + Compute token count based on inputs and outputs using tiktoken if token counts are not in the model response. + Responsible for closing the AI Client Span if instructed to by the `finish_span` argument. + """ + ttft: "Optional[float]" = None + data_buf: "list[list[str]]" = [] # one for each choice + + count_tokens_manually = True + async for x in old_iterator: with capture_internal_exceptions(): - if ttft is not None: - set_data_normalized( - span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, ttft - ) - if len(data_buf) > 0: - all_responses = ["".join(chunk) for chunk in data_buf] - if should_send_default_pii() and integration.include_prompts: - set_data_normalized( - span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses - ) - _calculate_token_usage( - messages, - response, - span, - all_responses, - integration.count_tokens, + if hasattr(x, "delta"): + if start_time is not None and ttft is None: + ttft = time.perf_counter() - start_time + if len(data_buf) == 0: + data_buf.append([]) + data_buf[0].append(x.delta or "") + + if isinstance(x, ResponseCompletedEvent): + span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, x.response.model) + + _calculate_responses_token_usage( + input=input, + response=x.response, + span=span, + streaming_message_responses=None, + count_tokens=integration.count_tokens, ) + count_tokens_manually = False - if finish_span: - span.__exit__(None, None, None) + yield x - if str(type(response._iterator)) == "": - response._iterator = new_iterator_async() - else: - response._iterator = new_iterator() + with capture_internal_exceptions(): + if ttft is not None: + set_data_normalized( + span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, ttft + ) + if len(data_buf) > 0: + all_responses = ["".join(chunk) for chunk in data_buf] + if should_send_default_pii() and integration.include_prompts: + set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses) + if count_tokens_manually: + _calculate_responses_token_usage( + input=input, + response=response, + span=span, + streaming_message_responses=all_responses, + count_tokens=integration.count_tokens, + ) + if finish_span: + span.__exit__(None, None, None) def _set_responses_api_output_data( @@ -723,127 +1028,6 @@ def _set_responses_api_output_data( ) -def _set_streaming_responses_api_output_data( - span: "Span", - response: "Any", - kwargs: "dict[str, Any]", - integration: "OpenAIIntegration", - start_time: "Optional[float]" = None, - finish_span: bool = True, -) -> None: - input = kwargs.get("input") - - if input is not None and isinstance(input, str): - input = [input] - - ttft: "Optional[float]" = None - data_buf: "list[list[str]]" = [] # one for each choice - - old_iterator = response._iterator - - def new_iterator() -> "Iterator[ChatCompletionChunk]": - nonlocal ttft - count_tokens_manually = True - for x in old_iterator: - with capture_internal_exceptions(): - if hasattr(x, "delta"): - if start_time is not None and ttft is None: - ttft = time.perf_counter() - start_time - if len(data_buf) == 0: - data_buf.append([]) - data_buf[0].append(x.delta or "") - - if isinstance(x, ResponseCompletedEvent): - span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, x.response.model) - - _calculate_token_usage( - input, - x.response, - span, - None, - integration.count_tokens, - ) - count_tokens_manually = False - - yield x - - with capture_internal_exceptions(): - if ttft is not None: - set_data_normalized( - span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, ttft - ) - if len(data_buf) > 0: - all_responses = ["".join(chunk) for chunk in data_buf] - if should_send_default_pii() and integration.include_prompts: - set_data_normalized( - span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses - ) - if count_tokens_manually: - _calculate_token_usage( - input, - response, - span, - all_responses, - integration.count_tokens, - ) - - if finish_span: - span.__exit__(None, None, None) - - async def new_iterator_async() -> "AsyncIterator[ChatCompletionChunk]": - nonlocal ttft - count_tokens_manually = True - async for x in old_iterator: - with capture_internal_exceptions(): - if hasattr(x, "delta"): - if start_time is not None and ttft is None: - ttft = time.perf_counter() - start_time - if len(data_buf) == 0: - data_buf.append([]) - data_buf[0].append(x.delta or "") - - if isinstance(x, ResponseCompletedEvent): - span.set_data(SPANDATA.GEN_AI_RESPONSE_MODEL, x.response.model) - - _calculate_token_usage( - input, - x.response, - span, - None, - integration.count_tokens, - ) - count_tokens_manually = False - - yield x - - with capture_internal_exceptions(): - if ttft is not None: - set_data_normalized( - span, SPANDATA.GEN_AI_RESPONSE_TIME_TO_FIRST_TOKEN, ttft - ) - if len(data_buf) > 0: - all_responses = ["".join(chunk) for chunk in data_buf] - if should_send_default_pii() and integration.include_prompts: - set_data_normalized( - span, SPANDATA.GEN_AI_RESPONSE_TEXT, all_responses - ) - if count_tokens_manually: - _calculate_token_usage( - input, - response, - span, - all_responses, - integration.count_tokens, - ) - if finish_span: - span.__exit__(None, None, None) - - if str(type(response._iterator)) == "": - response._iterator = new_iterator_async() - else: - response._iterator = new_iterator() - - def _set_embeddings_output_data( span: "Span", response: "Any", @@ -945,6 +1129,7 @@ def _new_embeddings_create_common(f: "Any", *args: "Any", **kwargs: "Any") -> "A name=f"embeddings {model}", origin=OpenAIIntegration.origin, ) as span: + span.set_data(SPANDATA.GEN_AI_SYSTEM, "openai") _set_embeddings_input_data(span, kwargs, integration) response = yield f, args, kwargs @@ -1036,15 +1221,49 @@ def _new_responses_create_common(f: "Any", *args: "Any", **kwargs: "Any") -> "An ) span.__enter__() + span.set_data(SPANDATA.GEN_AI_SYSTEM, "openai") + + # 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 + span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, is_streaming_response) + _set_responses_api_input_data(span, kwargs, integration) start_time = time.perf_counter() response = yield f, args, kwargs - is_streaming_response = kwargs.get("stream", False) - if is_streaming_response: - _set_streaming_responses_api_output_data( - span, response, kwargs, integration, start_time, finish_span=True + # Attribute check to fail gracefully if the attribute is not present in future `openai` versions. + if isinstance(response, Stream) and hasattr(response, "_iterator"): + input = kwargs.get("input") + + if input is not None and isinstance(input, str): + input = [input] + + response._iterator = _wrap_synchronous_responses_event_iterator( + span=span, + integration=integration, + start_time=start_time, + input=input, + response=response, + old_iterator=response._iterator, + finish_span=True, + ) + + # Attribute check to fail gracefully if the attribute is not present in future `openai` versions. + elif isinstance(response, AsyncStream) and hasattr(response, "_iterator"): + input = kwargs.get("input") + + if input is not None and isinstance(input, str): + input = [input] + + response._iterator = _wrap_asynchronous_responses_event_iterator( + span=span, + integration=integration, + start_time=start_time, + input=input, + response=response, + old_iterator=response._iterator, + finish_span=True, ) else: _set_responses_api_output_data( diff --git a/sentry_sdk/integrations/openai_agents/patches/agent_run.py b/sentry_sdk/integrations/openai_agents/patches/agent_run.py index 040b10b668..8f6468c1e9 100644 --- a/sentry_sdk/integrations/openai_agents/patches/agent_run.py +++ b/sentry_sdk/integrations/openai_agents/patches/agent_run.py @@ -8,7 +8,7 @@ end_invoke_agent_span, handoff_span, ) -from ..utils import _record_exception_on_span +from sentry_sdk.tracing_utils import set_span_errored from typing import TYPE_CHECKING @@ -99,9 +99,9 @@ async def _run_single_turn( try: result = await original_run_single_turn(*args, **kwargs) - except Exception as exc: + except Exception: if span is not None and span.timestamp is None: - _record_exception_on_span(span, exc) + set_span_errored(span) end_invoke_agent_span(context_wrapper, agent) reraise(*sys.exc_info()) @@ -153,11 +153,11 @@ async def _run_single_turn_streamed( try: result = await original_run_single_turn_streamed(*args, **kwargs) - except Exception as exc: + except Exception: exc_info = sys.exc_info() with capture_internal_exceptions(): if span is not None and span.timestamp is None: - _record_exception_on_span(span, exc) + set_span_errored(span) end_invoke_agent_span(context_wrapper, agent) _close_streaming_workflow_span(agent) reraise(*exc_info) diff --git a/sentry_sdk/integrations/openai_agents/patches/error_tracing.py b/sentry_sdk/integrations/openai_agents/patches/error_tracing.py index 9d6fd59e0f..0921f25e48 100644 --- a/sentry_sdk/integrations/openai_agents/patches/error_tracing.py +++ b/sentry_sdk/integrations/openai_agents/patches/error_tracing.py @@ -1,7 +1,7 @@ from functools import wraps import sentry_sdk -from ..utils import _record_exception_on_span +from sentry_sdk.tracing_utils import set_span_errored from typing import TYPE_CHECKING @@ -57,7 +57,7 @@ def sentry_attach_error_to_current_span( # Set the current Sentry span to errored current_span = sentry_sdk.get_current_span() if current_span is not None: - _record_exception_on_span(current_span, error) + set_span_errored(current_span) # Call the original function return original_attach_error(error, *args, **kwargs) diff --git a/sentry_sdk/integrations/openai_agents/patches/runner.py b/sentry_sdk/integrations/openai_agents/patches/runner.py index 78c055890e..fb35424db5 100644 --- a/sentry_sdk/integrations/openai_agents/patches/runner.py +++ b/sentry_sdk/integrations/openai_agents/patches/runner.py @@ -5,9 +5,10 @@ from sentry_sdk.consts import SPANDATA from sentry_sdk.integrations import DidNotEnable from sentry_sdk.utils import capture_internal_exceptions, reraise +from sentry_sdk.tracing_utils import set_span_errored from ..spans import agent_workflow_span, end_invoke_agent_span -from ..utils import _capture_exception, _record_exception_on_span +from ..utils import _capture_exception try: from agents.exceptions import AgentsException @@ -65,7 +66,7 @@ async def wrapper(*args: "Any", **kwargs: "Any") -> "Any": invoke_agent_span is not None and invoke_agent_span.timestamp is None ): - _record_exception_on_span(invoke_agent_span, exc) + set_span_errored(invoke_agent_span) end_invoke_agent_span(context_wrapper, agent) reraise(*exc_info) except Exception as exc: diff --git a/sentry_sdk/integrations/openai_agents/spans/execute_tool.py b/sentry_sdk/integrations/openai_agents/spans/execute_tool.py index e12dce4e3e..26072cfdba 100644 --- a/sentry_sdk/integrations/openai_agents/spans/execute_tool.py +++ b/sentry_sdk/integrations/openai_agents/spans/execute_tool.py @@ -23,9 +23,6 @@ def execute_tool_span( span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "execute_tool") - if tool.__class__.__name__ == "FunctionTool": - span.set_data(SPANDATA.GEN_AI_TOOL_TYPE, "function") - span.set_data(SPANDATA.GEN_AI_TOOL_NAME, tool.name) span.set_data(SPANDATA.GEN_AI_TOOL_DESCRIPTION, tool.description) diff --git a/sentry_sdk/integrations/openai_agents/utils.py b/sentry_sdk/integrations/openai_agents/utils.py index e496ed7fb5..ee504b3496 100644 --- a/sentry_sdk/integrations/openai_agents/utils.py +++ b/sentry_sdk/integrations/openai_agents/utils.py @@ -11,7 +11,6 @@ from sentry_sdk.consts import SPANDATA, SPANSTATUS, OP from sentry_sdk.integrations import DidNotEnable from sentry_sdk.scope import should_send_default_pii -from sentry_sdk.tracing import Span from sentry_sdk.tracing_utils import set_span_errored from sentry_sdk.utils import event_from_exception, safe_serialize from sentry_sdk.ai._openai_completions_api import _transform_system_instructions @@ -23,10 +22,9 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: - from typing import Any, Union + from typing import Any from agents import Usage, TResponseInputItem - from sentry_sdk.traces import StreamedSpan from sentry_sdk._types import TextPart try: @@ -47,26 +45,6 @@ def _capture_exception(exc: "Any") -> None: sentry_sdk.capture_event(event, hint=hint) -def _record_exception_on_span( - span: "Union[Span, StreamedSpan]", error: Exception -) -> "Any": - set_span_errored(span) - - if not isinstance(span, Span): - # TODO[span-first]: make this work with streamedspans - return - - span.set_data("span.status", "error") - - # Optionally capture the error details if we have them - if hasattr(error, "__class__"): - span.set_data("error.type", error.__class__.__name__) - if hasattr(error, "__str__"): - error_message = str(error) - if error_message: - span.set_data("error.message", error_message) - - def _set_agent_data(span: "sentry_sdk.tracing.Span", agent: "agents.Agent") -> None: span.set_data( SPANDATA.GEN_AI_SYSTEM, "openai" @@ -247,7 +225,6 @@ def _create_mcp_execute_tool_spans( description=f"execute_tool {output.name}", start_timestamp=span.start_timestamp, ) as execute_tool_span: - execute_tool_span.set_data(SPANDATA.GEN_AI_TOOL_TYPE, "mcp") execute_tool_span.set_data(SPANDATA.GEN_AI_TOOL_NAME, output.name) if should_send_default_pii(): execute_tool_span.set_data( diff --git a/sentry_sdk/integrations/opentelemetry/span_processor.py b/sentry_sdk/integrations/opentelemetry/span_processor.py index 407baef61c..8a589af308 100644 --- a/sentry_sdk/integrations/opentelemetry/span_processor.py +++ b/sentry_sdk/integrations/opentelemetry/span_processor.py @@ -34,6 +34,7 @@ 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" @@ -86,7 +87,8 @@ def __new__(cls) -> "SentrySpanProcessor": if not hasattr(cls, "instance"): cls.instance = super().__new__(cls) - return cls.instance + # "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: @add_global_event_processor @@ -123,13 +125,16 @@ def on_start( if client.options["instrumenter"] != INSTRUMENTER.OTEL: return - if not otel_span.get_span_context().is_valid: + 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(otel_span, parent_context) + trace_data = self._get_trace_data( + span_context, otel_span.parent, parent_context + ) parent_span_id = trace_data["parent_span_id"] sentry_parent_span = ( @@ -182,7 +187,7 @@ def on_end(self, otel_span: "OTelSpan") -> None: return span_context = otel_span.get_span_context() - if not span_context.is_valid: + if span_context is None or not span_context.is_valid: return span_id = format_span_id(span_context.span_id) @@ -254,13 +259,15 @@ def _get_otel_context(self, otel_span: "OTelSpan") -> "dict[str, Any]": return ctx def _get_trace_data( - self, otel_span: "OTelSpan", parent_context: "Optional[context_api.Context]" + 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 and its parent OTel context. + Extracts tracing information from one OTel span's context and its parent OTel context. """ trace_data: "dict[str, Any]" = {} - span_context = otel_span.get_span_context() span_id = format_span_id(span_context.span_id) trace_data["span_id"] = span_id @@ -269,7 +276,7 @@ def _get_trace_data( trace_data["trace_id"] = trace_id parent_span_id = ( - format_span_id(otel_span.parent.span_id) if otel_span.parent else None + format_span_id(parent_span_context.span_id) if parent_span_context else None ) trace_data["parent_span_id"] = parent_span_id diff --git a/sentry_sdk/integrations/pydantic_ai/__init__.py b/sentry_sdk/integrations/pydantic_ai/__init__.py index 0f0de53fa5..5868ccf07d 100644 --- a/sentry_sdk/integrations/pydantic_ai/__init__.py +++ b/sentry_sdk/integrations/pydantic_ai/__init__.py @@ -1,8 +1,11 @@ -from sentry_sdk.integrations import DidNotEnable, Integration +import functools +from sentry_sdk.integrations import DidNotEnable, Integration +from sentry_sdk.utils import capture_internal_exceptions try: import pydantic_ai # type: ignore # noqa: F401 + from pydantic_ai import Agent except ImportError: raise DidNotEnable("pydantic-ai not installed") @@ -10,14 +13,122 @@ from .patches import ( _patch_agent_run, _patch_graph_nodes, - _patch_model_request, _patch_tool_execution, ) +from .spans.ai_client import ai_client_span, update_ai_client_span + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import Any + from pydantic_ai import ModelRequestContext, RunContext + from pydantic_ai.messages import ModelResponse # type: ignore + from pydantic_ai.capabilities import Hooks # type: ignore + + +def register_hooks(hooks: "Hooks") -> None: + """ + Creates hooks for chat model calls and register the hooks by adding the hooks to the `capabilities` argument passed to `Agent.__init__()`. + """ + + @hooks.on.before_model_request # type: ignore + async def on_request( + ctx: "RunContext[None]", request_context: "ModelRequestContext" + ) -> "ModelRequestContext": + run_context_metadata = ctx.metadata + if not isinstance(run_context_metadata, dict): + return request_context + + span = ai_client_span( + messages=request_context.messages, + agent=None, + model=request_context.model, + model_settings=request_context.model_settings, + ) + + run_context_metadata["_sentry_span"] = span + span.__enter__() + + return request_context + + @hooks.on.after_model_request # type: ignore + async def on_response( + ctx: "RunContext[None]", + *, + request_context: "ModelRequestContext", + response: "ModelResponse", + ) -> "ModelResponse": + run_context_metadata = ctx.metadata + if not isinstance(run_context_metadata, dict): + return response + + span = run_context_metadata.pop("_sentry_span", None) + if span is None: + return response + + update_ai_client_span(span, response) + span.__exit__(None, None, None) + + return response + + @hooks.on.model_request_error # type: ignore + async def on_error( + ctx: "RunContext[None]", + *, + request_context: "ModelRequestContext", + error: "Exception", + ) -> "ModelResponse": + run_context_metadata = ctx.metadata + + if not isinstance(run_context_metadata, dict): + raise error + + span = run_context_metadata.pop("_sentry_span", None) + if span is None: + raise error + + with capture_internal_exceptions(): + span.__exit__(type(error), error, error.__traceback__) + + raise error + + original_init = Agent.__init__ + + @functools.wraps(original_init) + def patched_init(self: "Agent[Any, Any]", *args: "Any", **kwargs: "Any") -> None: + caps = list(kwargs.get("capabilities") or []) + caps.append(hooks) + kwargs["capabilities"] = caps + + metadata = kwargs.get("metadata") + if metadata is None: + kwargs["metadata"] = {} # Used as shared reference between hooks + + return original_init(self, *args, **kwargs) + + Agent.__init__ = patched_init + class PydanticAIIntegration(Integration): + """ + Typical interaction with the library: + 1. The user creates an Agent instance with configuration, including system instructions sent to every model call. + 2. The user calls `Agent.run()` or `Agent.run_stream()` to start an agent run. The latter can be used to incrementally receive progress. + - Each run invocation has `RunContext` objects that are passed to the library hooks. + 3. In a loop, the agent repeatedly calls the model, maintaining a conversation history that includes previous messages and tool results, which is passed to each call. + + Internally, Pydantic AI maintains an execution graph in which ModelRequestNode are responsible for model calls, including retries. + Hooks using the decorators provided by `pydantic_ai.capabilities` create and manage spans for model calls when these hooks are available (newer library versions). + The span is created in `on_request` and stored in the metadata of the `RunContext` object shared with `on_response` and `on_error`. + + The metadata dictionary on the RunContext instance is initialized with `{"_sentry_span": None}` in the `_create_run_wrapper()` and `_create_streaming_wrapper()` wrappers that + instrument `Agent.run()` and `Agent.run_stream()`, respectively. A non-empty dictionary is required for the metadata object to be a shared reference between hooks. + """ + identifier = "pydantic_ai" origin = f"auto.ai.{identifier}" + are_request_hooks_available = True def __init__( self, include_prompts: bool = True, handled_tool_call_exceptions: bool = True @@ -45,6 +156,17 @@ def setup_once() -> None: - Tool executions """ _patch_agent_run() - _patch_graph_nodes() - _patch_model_request() _patch_tool_execution() + + try: + from pydantic_ai.capabilities import Hooks + except ImportError: + Hooks = None + PydanticAIIntegration.are_request_hooks_available = False + + if Hooks is None: + _patch_graph_nodes() + return + + hooks = Hooks() + register_hooks(hooks) diff --git a/sentry_sdk/integrations/pydantic_ai/consts.py b/sentry_sdk/integrations/pydantic_ai/consts.py index 61e9b9bacf..afa66dc47d 100644 --- a/sentry_sdk/integrations/pydantic_ai/consts.py +++ b/sentry_sdk/integrations/pydantic_ai/consts.py @@ -1,8 +1 @@ -import re - SPAN_ORIGIN = "auto.ai.pydantic_ai" - -# Matches data URLs with base64-encoded content, e.g. "data:image/png;base64,iVBORw0K..." -DATA_URL_BASE64_REGEX = re.compile( - r"^data:(?:[a-zA-Z0-9][a-zA-Z0-9.+\-]*/[a-zA-Z0-9][a-zA-Z0-9.+\-]*)(?:;[a-zA-Z0-9\-]+=[^;,]*)*;base64,(?:[A-Za-z0-9+/\-_]+={0,2})$" -) diff --git a/sentry_sdk/integrations/pydantic_ai/patches/__init__.py b/sentry_sdk/integrations/pydantic_ai/patches/__init__.py index de28780728..d0ea6242b4 100644 --- a/sentry_sdk/integrations/pydantic_ai/patches/__init__.py +++ b/sentry_sdk/integrations/pydantic_ai/patches/__init__.py @@ -1,4 +1,3 @@ from .agent_run import _patch_agent_run # noqa: F401 from .graph_nodes import _patch_graph_nodes # noqa: F401 -from .model_request import _patch_model_request # 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 index eaa4385834..15f2b1994c 100644 --- a/sentry_sdk/integrations/pydantic_ai/patches/agent_run.py +++ b/sentry_sdk/integrations/pydantic_ai/patches/agent_run.py @@ -96,6 +96,9 @@ def _create_run_wrapper( original_func: The original run method is_streaming: Whether this is a streaming method (for future use) """ + from sentry_sdk.integrations.pydantic_ai import ( + PydanticAIIntegration, + ) # Required to avoid circular import @wraps(original_func) async def wrapper(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": @@ -107,6 +110,11 @@ async def wrapper(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": model = kwargs.get("model") model_settings = kwargs.get("model_settings") + if PydanticAIIntegration.are_request_hooks_available: + metadata = kwargs.get("metadata") + if metadata is None: + kwargs["metadata"] = {"_sentry_span": None} + # Create invoke_agent span with invoke_agent_span( user_prompt, self, model, model_settings, is_streaming @@ -140,6 +148,9 @@ def _create_streaming_wrapper( """ Wraps run_stream method that returns an async context manager. """ + from sentry_sdk.integrations.pydantic_ai import ( + PydanticAIIntegration, + ) # Required to avoid circular import @wraps(original_func) def wrapper(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": @@ -148,6 +159,11 @@ def wrapper(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": model = kwargs.get("model") model_settings = kwargs.get("model_settings") + if PydanticAIIntegration.are_request_hooks_available: + metadata = kwargs.get("metadata") + if metadata is None: + kwargs["metadata"] = {"_sentry_span": None} + # Call original function to get the context manager original_ctx_manager = original_func(self, *args, **kwargs) diff --git a/sentry_sdk/integrations/pydantic_ai/patches/model_request.py b/sentry_sdk/integrations/pydantic_ai/patches/model_request.py deleted file mode 100644 index 94a96161f3..0000000000 --- a/sentry_sdk/integrations/pydantic_ai/patches/model_request.py +++ /dev/null @@ -1,40 +0,0 @@ -from functools import wraps -from typing import TYPE_CHECKING - -from sentry_sdk.integrations import DidNotEnable - -try: - from pydantic_ai import models # type: ignore -except ImportError: - raise DidNotEnable("pydantic-ai not installed") - -from ..spans import ai_client_span, update_ai_client_span - - -if TYPE_CHECKING: - from typing import Any - - -def _patch_model_request() -> None: - """ - Patches model request execution to create AI client spans. - - In pydantic-ai, model requests are handled through the Model interface. - We need to patch the request method on models to create spans. - """ - - # Patch the base Model class's request method - if hasattr(models, "Model"): - original_request = models.Model.request - - @wraps(original_request) - async def wrapped_request( - self: "Any", messages: "Any", *args: "Any", **kwargs: "Any" - ) -> "Any": - # Pass all messages (full conversation history) - with ai_client_span(messages, None, self, None) as span: - result = await original_request(self, messages, *args, **kwargs) - update_ai_client_span(span, result) - return result - - models.Model.request = wrapped_request diff --git a/sentry_sdk/integrations/pydantic_ai/patches/tools.py b/sentry_sdk/integrations/pydantic_ai/patches/tools.py index 1f5cde8742..e719c7be78 100644 --- a/sentry_sdk/integrations/pydantic_ai/patches/tools.py +++ b/sentry_sdk/integrations/pydantic_ai/patches/tools.py @@ -14,14 +14,11 @@ from typing import Any try: - from pydantic_ai.mcp import MCPServer # type: ignore + try: + from pydantic_ai.tool_manager import ToolManager # type: ignore + except ImportError: + from pydantic_ai._tool_manager import ToolManager # type: ignore - HAS_MCP = True -except ImportError: - HAS_MCP = False - -try: - from pydantic_ai._tool_manager import ToolManager # type: ignore from pydantic_ai.exceptions import ToolRetryError # type: ignore except ImportError: raise DidNotEnable("pydantic-ai not installed") @@ -52,11 +49,6 @@ async def wrapped_execute_tool_call( tool = self.tools.get(name) if self.tools else None selected_tool_definition = getattr(tool, "tool_def", None) - # Determine tool type by checking tool.toolset - tool_type = "function" - if tool and HAS_MCP and isinstance(tool.toolset, MCPServer): - tool_type = "mcp" - # Get agent from contextvar agent = get_current_agent() @@ -73,7 +65,6 @@ async def wrapped_execute_tool_call( name, args_dict, agent, - tool_type=tool_type, tool_definition=selected_tool_definition, ) as span: try: @@ -131,11 +122,6 @@ async def wrapped_call_tool( tool = self.tools.get(name) if self.tools else None selected_tool_definition = getattr(tool, "tool_def", None) - # Determine tool type by checking tool.toolset - tool_type = "function" # default - if tool and HAS_MCP and isinstance(tool.toolset, MCPServer): - tool_type = "mcp" - # Get agent from contextvar agent = get_current_agent() @@ -152,7 +138,6 @@ async def wrapped_call_tool( name, args_dict, agent, - tool_type=tool_type, tool_definition=selected_tool_definition, ) as span: try: diff --git a/sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py b/sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py index 83ce6819e9..00b9cd4f57 100644 --- a/sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py +++ b/sentry_sdk/integrations/pydantic_ai/spans/execute_tool.py @@ -16,7 +16,6 @@ def execute_tool_span( tool_name: str, tool_args: "Any", agent: "Any", - tool_type: str = "function", tool_definition: "Optional[ToolDefinition]" = None, ) -> "sentry_sdk.tracing.Span": """Create a span for tool execution. @@ -25,7 +24,6 @@ def execute_tool_span( tool_name: The name of the tool being executed tool_args: The arguments passed to the tool agent: The agent executing the tool - tool_type: The type of tool ("function" for regular tools, "mcp" for MCP services) tool_definition: The definition of the tool, if available """ span = sentry_sdk.start_span( @@ -35,7 +33,6 @@ def execute_tool_span( ) span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "execute_tool") - span.set_data(SPANDATA.GEN_AI_TOOL_TYPE, tool_type) span.set_data(SPANDATA.GEN_AI_TOOL_NAME, tool_name) if tool_definition is not None and hasattr(tool_definition, "description"): diff --git a/sentry_sdk/integrations/pydantic_ai/spans/utils.py b/sentry_sdk/integrations/pydantic_ai/spans/utils.py index 70e47dc034..8f158b6da2 100644 --- a/sentry_sdk/integrations/pydantic_ai/spans/utils.py +++ b/sentry_sdk/integrations/pydantic_ai/spans/utils.py @@ -5,7 +5,7 @@ from sentry_sdk.ai.utils import get_modality_from_mime_type from sentry_sdk.consts import SPANDATA -from ..consts import DATA_URL_BASE64_REGEX +from sentry_sdk.ai.consts import DATA_URL_BASE64_REGEX from typing import TYPE_CHECKING diff --git a/sentry_sdk/integrations/pymongo.py b/sentry_sdk/integrations/pymongo.py index 86399b54d1..59daab34da 100644 --- a/sentry_sdk/integrations/pymongo.py +++ b/sentry_sdk/integrations/pymongo.py @@ -88,6 +88,7 @@ def _get_db_data(event: "Any") -> "Dict[str, Any]": data = {} data[SPANDATA.DB_SYSTEM] = "mongodb" + data[SPANDATA.DB_DRIVER_NAME] = "pymongo" db_name = event.database_name if db_name is not None: @@ -128,6 +129,7 @@ def started(self, event: "CommandStartedEvent") -> None: tags = { "db.name": event.database_name, SPANDATA.DB_SYSTEM: "mongodb", + SPANDATA.DB_DRIVER_NAME: "pymongo", SPANDATA.DB_OPERATION: event.command_name, SPANDATA.DB_MONGODB_COLLECTION: command.get(event.command_name), } diff --git a/sentry_sdk/integrations/pyreqwest.py b/sentry_sdk/integrations/pyreqwest.py new file mode 100644 index 0000000000..9861a83bf1 --- /dev/null +++ b/sentry_sdk/integrations/pyreqwest.py @@ -0,0 +1,136 @@ +import sentry_sdk +from sentry_sdk import start_span +from sentry_sdk.consts import OP, SPANDATA +from sentry_sdk.integrations import Integration, DidNotEnable +from sentry_sdk.tracing import BAGGAGE_HEADER_NAME +from sentry_sdk.tracing_utils import ( + should_propagate_trace, + add_http_request_source, + add_sentry_baggage_to_headers, +) +from sentry_sdk.utils import ( + SENSITIVE_DATA_SUBSTITUTE, + capture_internal_exceptions, + logger, + parse_url, +) + +from contextlib import contextmanager +from typing import Any, Generator + +try: + from pyreqwest.client import ClientBuilder, SyncClientBuilder # type: ignore[import-not-found] + from pyreqwest.request import ( # type: ignore[import-not-found] + Request, + OneOffRequestBuilder, + SyncOneOffRequestBuilder, + ) + from pyreqwest.middleware import Next, SyncNext # type: ignore[import-not-found] + from pyreqwest.response import Response, SyncResponse # type: ignore[import-not-found] +except ImportError: + raise DidNotEnable("pyreqwest not installed or incompatible version installed") + + +class PyreqwestIntegration(Integration): + identifier = "pyreqwest" + origin = f"auto.http.{identifier}" + + @staticmethod + def setup_once() -> None: + _patch_pyreqwest() + + +def _patch_pyreqwest() -> None: + # Patch Client Builders + _patch_builder_method(ClientBuilder, "build", sentry_async_middleware) + _patch_builder_method(SyncClientBuilder, "build", sentry_sync_middleware) + + # Patch Request Builders + _patch_builder_method(OneOffRequestBuilder, "send", sentry_async_middleware) + _patch_builder_method(SyncOneOffRequestBuilder, "send", sentry_sync_middleware) + + +def _patch_builder_method(cls: type, method_name: str, middleware: "Any") -> None: + if not hasattr(cls, method_name): + return + + original_method = getattr(cls, method_name) + + def sentry_patched_method(self: "Any", *args: "Any", **kwargs: "Any") -> "Any": + if not getattr(self, "_sentry_instrumented", False): + integration = sentry_sdk.get_client().get_integration(PyreqwestIntegration) + if integration is not None: + self.with_middleware(middleware) + try: + self._sentry_instrumented = True + except (TypeError, AttributeError): + # In case the instance itself is immutable or doesn't allow extra attributes + pass + return original_method(self, *args, **kwargs) + + setattr(cls, method_name, sentry_patched_method) + + +@contextmanager +def _sentry_pyreqwest_span(request: "Request") -> "Generator[Any, None, None]": + parsed_url = None + with capture_internal_exceptions(): + parsed_url = parse_url(str(request.url), sanitize=False) + + with start_span( + op=OP.HTTP_CLIENT, + name=f"{request.method} {parsed_url.url if parsed_url else SENSITIVE_DATA_SUBSTITUTE}", + origin=PyreqwestIntegration.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) + + 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 + + yield span + + with capture_internal_exceptions(): + add_http_request_source(span) + + +async def sentry_async_middleware( + request: "Request", next_handler: "Next" +) -> "Response": + if sentry_sdk.get_client().get_integration(PyreqwestIntegration) is None: + return await next_handler.run(request) + + with _sentry_pyreqwest_span(request) as span: + response = await next_handler.run(request) + span.set_http_status(response.status) + + return response + + +def sentry_sync_middleware( + request: "Request", next_handler: "SyncNext" +) -> "SyncResponse": + if sentry_sdk.get_client().get_integration(PyreqwestIntegration) is None: + return next_handler.run(request) + + with _sentry_pyreqwest_span(request) as span: + response = next_handler.run(request) + span.set_http_status(response.status) + + return response diff --git a/sentry_sdk/integrations/redis/modules/queries.py b/sentry_sdk/integrations/redis/modules/queries.py index 3e8a820f44..c7780099c3 100644 --- a/sentry_sdk/integrations/redis/modules/queries.py +++ b/sentry_sdk/integrations/redis/modules/queries.py @@ -44,6 +44,7 @@ def _get_db_span_description( def _set_db_data_on_span(span: "Span", connection_params: "dict[str, Any]") -> None: span.set_data(SPANDATA.DB_SYSTEM, "redis") + span.set_data(SPANDATA.DB_DRIVER_NAME, "redis-py") db = connection_params.get("db") if db is not None: diff --git a/sentry_sdk/integrations/sqlalchemy.py b/sentry_sdk/integrations/sqlalchemy.py index 7d3ed95373..a4354f4228 100644 --- a/sentry_sdk/integrations/sqlalchemy.py +++ b/sentry_sdk/integrations/sqlalchemy.py @@ -137,6 +137,13 @@ def _set_db_data(span: "Span", conn: "Any") -> None: if db_system is not None: span.set_data(SPANDATA.DB_SYSTEM, db_system) + try: + driver = conn.dialect.driver + if driver: + span.set_data(SPANDATA.DB_DRIVER_NAME, driver) + except Exception: + pass + if conn.engine.url is None: return diff --git a/sentry_sdk/integrations/starlette.py b/sentry_sdk/integrations/starlette.py index 0b797ebcde..dac9887e2f 100644 --- a/sentry_sdk/integrations/starlette.py +++ b/sentry_sdk/integrations/starlette.py @@ -552,7 +552,11 @@ def patch_templates() -> None: except ImportError: return # Nothing to do - from starlette.templating import Jinja2Templates # type: ignore + # https://github.com/Kludex/starlette/commit/96479daca2e4bd8157f68d914fd162aa94eff73a + try: + from starlette.templating import Jinja2Templates # type: ignore + except ImportError: + return old_jinja2templates_init = Jinja2Templates.__init__ diff --git a/sentry_sdk/integrations/wsgi.py b/sentry_sdk/integrations/wsgi.py index ea7ebbea4d..8814a82858 100644 --- a/sentry_sdk/integrations/wsgi.py +++ b/sentry_sdk/integrations/wsgi.py @@ -13,7 +13,9 @@ ) from sentry_sdk.scope import should_send_default_pii, use_isolation_scope from sentry_sdk.sessions import track_session -from sentry_sdk.tracing import Transaction, TransactionSource +from sentry_sdk.traces import StreamedSpan, SegmentSource +from sentry_sdk.tracing import Span, TransactionSource +from sentry_sdk.tracing_utils import has_span_streaming_enabled from sentry_sdk.utils import ( ContextVar, capture_internal_exceptions, @@ -22,7 +24,18 @@ ) if TYPE_CHECKING: - from typing import Any, Callable, Dict, Iterator, Optional, Protocol, Tuple, TypeVar + from typing import ( + Any, + Callable, + ContextManager, + Dict, + Iterator, + Optional, + Protocol, + Tuple, + TypeVar, + Union, + ) from sentry_sdk._types import Event, EventProcessor from sentry_sdk.utils import ExcInfo @@ -42,6 +55,7 @@ def __call__( _wsgi_middleware_applied = ContextVar("sentry_wsgi_middleware_applied") +_DEFAULT_TRANSACTION_NAME = "generic WSGI request" def wsgi_decoding_dance(s: str, charset: str = "utf-8", errors: str = "replace") -> str: @@ -57,8 +71,12 @@ def get_request_url( path_info = environ.get("PATH_INFO", "").lstrip("/") path = f"{script_name}/{path_info}" + scheme = environ.get("wsgi.url_scheme") + if use_x_forwarded_for: + scheme = environ.get("HTTP_X_FORWARDED_PROTO", scheme) + return "%s://%s/%s" % ( - environ.get("wsgi.url_scheme"), + scheme, get_host(environ, use_x_forwarded_for), wsgi_decoding_dance(path).lstrip("/"), ) @@ -90,6 +108,9 @@ def __call__( if _wsgi_middleware_applied.get(False): 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: with sentry_sdk.isolation_scope() as scope: @@ -104,34 +125,72 @@ def __call__( ) method = environ.get("REQUEST_METHOD", "").upper() - transaction = None + + span_ctx: "Optional[ContextManager[Union[Span, StreamedSpan, None]]]" = None if method in self.http_methods_to_capture: - transaction = continue_trace( - environ, - op=OP.HTTP_SERVER, - name="generic WSGI request", - source=TransactionSource.ROUTE, - origin=self.span_origin, - ) + if span_streaming: + sentry_sdk.traces.continue_trace( + dict(_get_headers(environ)) + ) + scope.set_custom_sampling_context({"wsgi_environ": environ}) + + span_ctx = sentry_sdk.traces.start_span( + name=_DEFAULT_TRANSACTION_NAME, + attributes={ + "sentry.span.source": SegmentSource.ROUTE, + "sentry.origin": self.span_origin, + "sentry.op": OP.HTTP_SERVER, + }, + ) + 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() + + with span_ctx as span: + if isinstance(span, StreamedSpan): + with capture_internal_exceptions(): + for attr, value in _get_request_attributes( + environ, self.use_x_forwarded_for + ).items(): + span.set_attribute(attr, value) - transaction_context = ( - sentry_sdk.start_transaction( - transaction, - custom_sampling_context={"wsgi_environ": environ}, - ) - if transaction is not None - else nullcontext() - ) - with transaction_context: try: response = self.app( environ, - partial( - _sentry_start_response, start_response, transaction - ), + partial(_sentry_start_response, start_response, span), ) except BaseException: reraise(*_capture_exception()) + finally: + if isinstance(span, StreamedSpan): + already_set = ( + span.name != _DEFAULT_TRANSACTION_NAME + and span.get_attributes().get("sentry.span.source") + in [ + SegmentSource.COMPONENT.value, + SegmentSource.ROUTE.value, + SegmentSource.CUSTOM.value, + ] + ) + if not already_set: + with capture_internal_exceptions(): + span.name = _DEFAULT_TRANSACTION_NAME + span.set_attribute( + "sentry.span.source", + SegmentSource.ROUTE.value, + ) finally: _wsgi_middleware_applied.set(False) @@ -163,15 +222,19 @@ def __call__( def _sentry_start_response( old_start_response: "StartResponse", - transaction: "Optional[Transaction]", + span: "Optional[Union[Span, StreamedSpan]]", status: str, response_headers: "WsgiResponseHeaders", exc_info: "Optional[WsgiExcInfo]" = None, ) -> "WsgiResponseIter": # type: ignore[type-var] with capture_internal_exceptions(): status_int = int(status.split(" ", 1)[0]) - if transaction is not None: - transaction.set_http_status(status_int) + 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) if exc_info is None: # The Django Rest Framework WSGI test client, and likely other @@ -322,3 +385,50 @@ def event_processor(event: "Event", hint: "Dict[str, Any]") -> "Event": return event return event_processor + + +def _get_request_attributes( + environ: "Dict[str, str]", + use_x_forwarded_for: bool = False, +) -> "Dict[str, Any]": + """ + Return span attributes related to the HTTP request from the WSGI environ. + """ + attributes: "dict[str, Any]" = {} + + method = environ.get("REQUEST_METHOD") + if method: + attributes["http.request.method"] = method.upper() + + headers = _filter_headers(dict(_get_headers(environ)), use_annotated_value=False) + for header, value in headers.items(): + attributes[f"http.request.header.{header.lower()}"] = value + + query_string = environ.get("QUERY_STRING") + if query_string: + attributes["http.query"] = query_string + + attributes["url.full"] = get_request_url(environ, use_x_forwarded_for) + + url_scheme = environ.get("wsgi.url_scheme") + if url_scheme: + attributes["network.protocol.name"] = url_scheme + + server_name = environ.get("SERVER_NAME") + if server_name: + attributes["server.address"] = server_name + + server_port = environ.get("SERVER_PORT") + if server_port: + try: + attributes["server.port"] = int(server_port) + except ValueError: + pass + + if should_send_default_pii(): + client_ip = get_client_ip(environ) + if client_ip: + attributes["client.address"] = client_ip + attributes["user.ip_address"] = client_ip + + return attributes diff --git a/sentry_sdk/profiler/continuous_profiler.py b/sentry_sdk/profiler/continuous_profiler.py index aeeae3fb1d..5a42785fdf 100644 --- a/sentry_sdk/profiler/continuous_profiler.py +++ b/sentry_sdk/profiler/continuous_profiler.py @@ -506,8 +506,6 @@ def teardown(self) -> None: self.thread.join() self.thread = None - self.buffer = None - class GeventContinuousScheduler(ContinuousScheduler): """ @@ -580,8 +578,6 @@ def teardown(self) -> None: self.thread.join() self.thread = None - self.buffer = None - PROFILE_BUFFER_SECONDS = 60 diff --git a/sentry_sdk/scope.py b/sentry_sdk/scope.py index e92c0bf7fc..750e602127 100644 --- a/sentry_sdk/scope.py +++ b/sentry_sdk/scope.py @@ -714,7 +714,7 @@ def get_active_propagation_context(self) -> "PropagationContext": def set_custom_sampling_context( self, custom_sampling_context: "dict[str, Any]" ) -> None: - self.get_active_propagation_context()._set_custom_sampling_context( + self.get_current_scope().get_active_propagation_context()._set_custom_sampling_context( custom_sampling_context ) diff --git a/sentry_sdk/traces.py b/sentry_sdk/traces.py index 944e17e5d7..f44ef71f5b 100644 --- a/sentry_sdk/traces.py +++ b/sentry_sdk/traces.py @@ -259,6 +259,7 @@ def __init__( self._name: str = name self._active: bool = active self._attributes: "Attributes" = {} + if attributes: for attribute, value in attributes.items(): self.set_attribute(attribute, value) @@ -287,7 +288,6 @@ def __init__( self._span_id: "Optional[str]" = None self._status = SpanStatus.OK.value - self.set_attribute("sentry.span.source", SegmentSource.CUSTOM.value) self._update_active_thread() diff --git a/sentry_sdk/transport.py b/sentry_sdk/transport.py index dcfe55406b..c9fb596c44 100644 --- a/sentry_sdk/transport.py +++ b/sentry_sdk/transport.py @@ -1,4 +1,5 @@ from abc import ABC, abstractmethod +import asyncio import io import os import gzip @@ -15,13 +16,37 @@ except ImportError: brotli = None +try: + import httpcore +except ImportError: + httpcore = None # type: ignore[assignment,unused-ignore] + +try: + import h2 # noqa: F401 + + HTTP2_ENABLED = httpcore is not None +except ImportError: + HTTP2_ENABLED = False + +try: + import anyio # noqa: F401 + + ASYNC_TRANSPORT_AVAILABLE = httpcore is not None +except ImportError: + ASYNC_TRANSPORT_AVAILABLE = False + import urllib3 import certifi import sentry_sdk from sentry_sdk.consts import EndpointType -from sentry_sdk.utils import Dsn, logger, capture_internal_exceptions -from sentry_sdk.worker import BackgroundWorker +from sentry_sdk.utils import ( + Dsn, + logger, + capture_internal_exceptions, + mark_sentry_task_internal, +) +from sentry_sdk.worker import BackgroundWorker, Worker, AsyncWorker from sentry_sdk.envelope import Envelope, Item, PayloadRef from typing import TYPE_CHECKING, cast, List, Dict @@ -58,6 +83,19 @@ pass +def _get_httpcore_header_value(response: "Any", header: str) -> "Optional[str]": + """Case-insensitive header lookup for httpcore-style responses.""" + header_lower = header.lower() + return next( + ( + val.decode("ascii") + for key, val in response.headers + if key.decode("ascii").lower() == header_lower + ), + None, + ) + + class Transport(ABC): """Baseclass for all transports. @@ -170,8 +208,8 @@ def _parse_rate_limits( continue -class BaseHttpTransport(Transport): - """The base HTTP transport.""" +class HttpTransportCore(Transport): + """Shared base class for sync and async transports.""" TIMEOUT = 30 # seconds @@ -181,7 +219,7 @@ def __init__(self: "Self", options: "Dict[str, Any]") -> None: Transport.__init__(self, options) assert self.parsed_dsn is not None self.options: "Dict[str, Any]" = options - self._worker = BackgroundWorker(queue_size=options["transport_queue_size"]) + self._worker = self._create_worker(options) self._auth = self.parsed_dsn.to_auth("sentry.python/%s" % VERSION) self._disabled_until: "Dict[Optional[EventDataCategory], datetime]" = {} # We only use this Retry() class for the `get_retry_after` method it exposes @@ -235,6 +273,9 @@ def __init__(self: "Self", options: "Dict[str, Any]") -> None: elif self._compression_algo == "br": self._compression_level = 4 + def _create_worker(self: "Self", options: "Dict[str, Any]") -> "Worker": + raise NotImplementedError() + def record_lost_event( self, reason: str, @@ -305,12 +346,11 @@ def _update_rate_limits( seconds=retry_after ) - def _send_request( + def _handle_request_error( self: "Self", - body: bytes, - headers: "Dict[str, str]", - endpoint_type: "EndpointType" = EndpointType.ENVELOPE, - envelope: "Optional[Envelope]" = None, + envelope: "Optional[Envelope]", + loss_reason: str = "network", + record_reason: str = "network_error", ) -> None: def record_loss(reason: str) -> None: if envelope is None: @@ -319,59 +359,59 @@ def record_loss(reason: str) -> None: for item in envelope.items: self.record_lost_event(reason, item=item) + self.on_dropped_event(loss_reason) + record_loss(record_reason) + + def _handle_response( + self: "Self", + response: "Union[urllib3.BaseHTTPResponse, httpcore.Response]", + envelope: "Optional[Envelope]", + ) -> None: + self._update_rate_limits(response) + + if response.status == 413: + size_exceeded_message = ( + "HTTP 413: Event dropped due to exceeded envelope size limit" + ) + response_message = getattr( + response, "data", getattr(response, "content", None) + ) + if response_message is not None: + size_exceeded_message += f" (body: {response_message})" + + logger.error(size_exceeded_message) + self._handle_request_error( + envelope=envelope, loss_reason="status_413", record_reason="send_error" + ) + + elif response.status == 429: + # if we hit a 429. Something was rate limited but we already + # acted on this in `self._update_rate_limits`. Note that we + # do not want to record event loss here as we will have recorded + # an outcome in relay already. + self.on_dropped_event("status_429") + pass + + elif response.status >= 300 or response.status < 200: + logger.error( + "Unexpected status code: %s (body: %s)", + response.status, + getattr(response, "data", getattr(response, "content", None)), + ) + self._handle_request_error( + envelope=envelope, loss_reason="status_{}".format(response.status) + ) + + def _update_headers( + self: "Self", + headers: "Dict[str, str]", + ) -> None: headers.update( { "User-Agent": str(self._auth.client), "X-Sentry-Auth": str(self._auth.to_header()), } ) - try: - response = self._request( - "POST", - endpoint_type, - body, - headers, - ) - except Exception: - self.on_dropped_event("network") - record_loss("network_error") - raise - - try: - self._update_rate_limits(response) - - if response.status == 413: - size_exceeded_message = ( - "HTTP 413: Event dropped due to exceeded envelope size limit" - ) - response_message = getattr( - response, "data", getattr(response, "content", None) - ) - if response_message is not None: - size_exceeded_message += f" (body: {response_message})" - - logger.error(size_exceeded_message) - self.on_dropped_event("status_413") - record_loss("send_error") - - elif response.status == 429: - # if we hit a 429. Something was rate limited but we already - # acted on this in `self._update_rate_limits`. Note that we - # do not want to record event loss here as we will have recorded - # an outcome in relay already. - self.on_dropped_event("status_429") - pass - - elif response.status >= 300 or response.status < 200: - logger.error( - "Unexpected status code: %s (body: %s)", - response.status, - getattr(response, "data", getattr(response, "content", None)), - ) - self.on_dropped_event("status_{}".format(response.status)) - record_loss("network_error") - finally: - response.close() def on_dropped_event(self: "Self", _reason: str) -> None: return None @@ -408,11 +448,6 @@ def _fetch_pending_client_report( type="client_report", ) - def _flush_client_reports(self: "Self", force: bool = False) -> None: - client_report = self._fetch_pending_client_report(force=force, interval=60) - if client_report is not None: - self.capture_envelope(Envelope(items=[client_report])) - def _check_disabled(self, category: str) -> bool: def _disabled(bucket: "Any") -> bool: ts = self._disabled_until.get(bucket) @@ -431,7 +466,9 @@ def _is_worker_full(self: "Self") -> bool: def is_healthy(self: "Self") -> bool: return not (self._is_worker_full() or self._is_rate_limited()) - def _send_envelope(self: "Self", envelope: "Envelope") -> None: + def _prepare_envelope( + self: "Self", envelope: "Envelope" + ) -> "Optional[Tuple[Envelope, io.BytesIO, Dict[str, str]]]": # remove all items from the envelope which are over quota new_items = [] for item in envelope.items: @@ -468,19 +505,13 @@ def _send_envelope(self: "Self", envelope: "Envelope") -> None: self.parsed_dsn.host, ) - headers = { + headers: "Dict[str, str]" = { "Content-Type": "application/x-sentry-envelope", } if content_encoding: headers["Content-Encoding"] = content_encoding - self._send_request( - body.getvalue(), - headers=headers, - endpoint_type=EndpointType.ENVELOPE, - envelope=envelope, - ) - return None + return envelope, body, headers def _serialize_envelope( self: "Self", envelope: "Envelope" @@ -505,6 +536,77 @@ def _serialize_envelope( return content_encoding, body + def _get_httpcore_pool_options( + self: "Self", http2: bool = False + ) -> "Dict[str, Any]": + """Shared pool options for httpcore-based transports (Http2 and Async).""" + options: "Dict[str, Any]" = { + "http2": http2, + "retries": 3, + } + + socket_options: "Optional[List[Tuple[int, int, int | bytes]]]" = None + + if self.options["socket_options"] is not None: + socket_options = self.options["socket_options"] + + if socket_options is None: + socket_options = [] + + used_options = {(o[0], o[1]) for o in socket_options} + for default_option in KEEP_ALIVE_SOCKET_OPTIONS: + if (default_option[0], default_option[1]) not in used_options: + socket_options.append(default_option) + + if socket_options is not None: + options["socket_options"] = socket_options + + ssl_context = ssl.create_default_context() + ssl_context.load_verify_locations( + self.options["ca_certs"] + or os.environ.get("SSL_CERT_FILE") + or os.environ.get("REQUESTS_CA_BUNDLE") + or certifi.where() + ) + cert_file = self.options["cert_file"] or os.environ.get("CLIENT_CERT_FILE") + key_file = self.options["key_file"] or os.environ.get("CLIENT_KEY_FILE") + if cert_file is not None: + ssl_context.load_cert_chain(cert_file, key_file) + + options["ssl_context"] = ssl_context + return options + + def _resolve_proxy(self: "Self") -> "Optional[str]": + """Resolve proxy URL from options and environment. Returns proxy URL or None.""" + if self.parsed_dsn is None: + return None + + no_proxy = self._in_no_proxy(self.parsed_dsn) + proxy = None + + # try HTTPS first + https_proxy = self.options["https_proxy"] + if self.parsed_dsn.scheme == "https" and (https_proxy != ""): + proxy = https_proxy or (not no_proxy and getproxies().get("https")) + + # maybe fallback to HTTP proxy + http_proxy = self.options["http_proxy"] + if not proxy and (http_proxy != ""): + proxy = http_proxy or (not no_proxy and getproxies().get("http")) + + return proxy or None + + @property + def _timeout_extensions(self: "Self") -> "Dict[str, Any]": + return { + "timeout": { + "pool": self.TIMEOUT, + "connect": self.TIMEOUT, + "write": self.TIMEOUT, + "read": self.TIMEOUT, + } + } + def _get_pool_options(self: "Self") -> "Dict[str, Any]": raise NotImplementedError() @@ -520,7 +622,7 @@ def _in_no_proxy(self: "Self", parsed_dsn: "Dsn") -> bool: def _make_pool( self: "Self", - ) -> "Union[PoolManager, ProxyManager, httpcore.SOCKSProxy, httpcore.HTTPProxy, httpcore.ConnectionPool]": + ) -> "Union[PoolManager, ProxyManager, httpcore.SOCKSProxy, httpcore.HTTPProxy, httpcore.ConnectionPool, httpcore.AsyncSOCKSProxy, httpcore.AsyncHTTPProxy, httpcore.AsyncConnectionPool]": raise NotImplementedError() def _request( @@ -532,6 +634,59 @@ def _request( ) -> "Union[urllib3.BaseHTTPResponse, httpcore.Response]": raise NotImplementedError() + def kill(self: "Self") -> None: + logger.debug("Killing HTTP transport") + self._worker.kill() + + +# Keep BaseHttpTransport as an alias for backwards compatibility +# and for the sync transport implementation +class BaseHttpTransport(HttpTransportCore): + """The base HTTP transport (synchronous).""" + + def _send_envelope(self: "Self", envelope: "Envelope") -> None: + _prepared_envelope = self._prepare_envelope(envelope) + if _prepared_envelope is not None: + envelope, body, headers = _prepared_envelope + self._send_request( + body.getvalue(), + headers=headers, + endpoint_type=EndpointType.ENVELOPE, + envelope=envelope, + ) + return None + + def _send_request( + self: "Self", + body: bytes, + headers: "Dict[str, str]", + endpoint_type: "EndpointType", + envelope: "Optional[Envelope]" = None, + ) -> None: + self._update_headers(headers) + try: + response = self._request( + "POST", + endpoint_type, + body, + headers, + ) + except Exception: + self._handle_request_error(envelope=envelope, loss_reason="network") + raise + try: + self._handle_response(response=response, envelope=envelope) + finally: + response.close() + + def _create_worker(self: "Self", options: "Dict[str, Any]") -> "Worker": + return BackgroundWorker(queue_size=options["transport_queue_size"]) + + def _flush_client_reports(self: "Self", force: bool = False) -> None: + client_report = self._fetch_pending_client_report(force=force, interval=60) + if client_report is not None: + self.capture_envelope(Envelope(items=[client_report])) + def capture_envelope( self, envelope: "Envelope", @@ -557,10 +712,6 @@ def flush( self._worker.submit(lambda: self._flush_client_reports(force=True)) self._worker.flush(timeout, callback) - def kill(self: "Self") -> None: - logger.debug("Killing HTTP transport") - self._worker.kill() - @staticmethod def _warn_hub_cls() -> None: """Convenience method to warn users about the deprecation of the `hub_cls` attribute.""" @@ -688,10 +839,168 @@ def _request( ) -try: - import httpcore - import h2 # noqa: F401 -except ImportError: +class AsyncHttpTransport(HttpTransportCore): + def __init__(self: "Self", options: "Dict[str, Any]") -> None: + if not ASYNC_TRANSPORT_AVAILABLE: + raise RuntimeError( + "AsyncHttpTransport requires httpcore[asyncio]. " + "Install it with: pip install sentry-sdk[asyncio]" + ) + super().__init__(options) + # Requires event loop at init time + self.loop = asyncio.get_running_loop() + + def _create_worker(self: "Self", options: "Dict[str, Any]") -> "Worker": + return AsyncWorker(queue_size=options["transport_queue_size"]) + + def _get_header_value( + self: "Self", response: "Any", header: str + ) -> "Optional[str]": + return _get_httpcore_header_value(response, header) + + async def _send_envelope(self: "Self", envelope: "Envelope") -> None: + _prepared_envelope = self._prepare_envelope(envelope) + if _prepared_envelope is not None: + envelope, body, headers = _prepared_envelope + await self._send_request( + body.getvalue(), + headers=headers, + endpoint_type=EndpointType.ENVELOPE, + envelope=envelope, + ) + return None + + async def _send_request( + self: "Self", + body: bytes, + headers: "Dict[str, str]", + endpoint_type: "EndpointType", + envelope: "Optional[Envelope]" = None, + ) -> None: + self._update_headers(headers) + try: + response = await self._request( + "POST", + endpoint_type, + body, + headers, + ) + except Exception: + self._handle_request_error(envelope=envelope, loss_reason="network") + raise + try: + self._handle_response(response=response, envelope=envelope) + finally: + await response.aclose() + + async def _request( # type: ignore[override] + self: "Self", + method: str, + endpoint_type: "EndpointType", + body: "Any", + headers: "Mapping[str, str]", + ) -> "httpcore.Response": + return await self._pool.request( # type: ignore[misc,unused-ignore] + method, + self._auth.get_api_url(endpoint_type), + content=body, + headers=headers, # type: ignore[arg-type,unused-ignore] + extensions=self._timeout_extensions, + ) + + async def _flush_client_reports(self: "Self", force: bool = False) -> None: + client_report = self._fetch_pending_client_report(force=force, interval=60) + if client_report is not None: + self.capture_envelope(Envelope(items=[client_report])) + + def _capture_envelope(self: "Self", envelope: "Envelope") -> None: + async def send_envelope_wrapper() -> None: + with capture_internal_exceptions(): + await self._send_envelope(envelope) + await self._flush_client_reports() + + if not self._worker.submit(send_envelope_wrapper): + self.on_dropped_event("full_queue") + for item in envelope.items: + self.record_lost_event("queue_overflow", item=item) + + def capture_envelope(self: "Self", envelope: "Envelope") -> None: + # Synchronous entry point + if self.loop and self.loop.is_running(): + self.loop.call_soon_threadsafe(self._capture_envelope, envelope) + else: + # The event loop is no longer running + logger.warning("Async Transport is not running in an event loop.") + self.on_dropped_event("internal_sdk_error") + for item in envelope.items: + self.record_lost_event("internal_sdk_error", item=item) + + def flush( # type: ignore[override] + self: "Self", + timeout: float, + callback: "Optional[Callable[[int, float], None]]" = None, + ) -> "Optional[asyncio.Task[None]]": + logger.debug("Flushing HTTP transport") + + if timeout > 0: + self._worker.submit(lambda: self._flush_client_reports(force=True)) + return self._worker.flush(timeout, callback) # type: ignore[func-returns-value] + return None + + def _get_pool_options(self: "Self") -> "Dict[str, Any]": + return self._get_httpcore_pool_options( + http2=HTTP2_ENABLED + and self.parsed_dsn is not None + and self.parsed_dsn.scheme == "https" + ) + + def _make_pool( + self: "Self", + ) -> "Union[httpcore.AsyncSOCKSProxy, httpcore.AsyncHTTPProxy, httpcore.AsyncConnectionPool]": + if self.parsed_dsn is None: + raise ValueError("Cannot create HTTP-based transport without valid DSN") + + proxy = self._resolve_proxy() + opts = self._get_pool_options() + + if proxy: + proxy_headers = self.options["proxy_headers"] + if proxy_headers: + opts["proxy_headers"] = proxy_headers + + if proxy.startswith("socks"): + try: + socks_opts = opts.copy() + if "socket_options" in socks_opts: + socket_options = socks_opts.pop("socket_options") + if socket_options: + logger.warning( + "You have defined socket_options but using a SOCKS proxy which doesn't support these. We'll ignore socket_options." + ) + return httpcore.AsyncSOCKSProxy(proxy_url=proxy, **socks_opts) + except RuntimeError: + logger.warning( + "You have configured a SOCKS proxy (%s) but support for SOCKS proxies is not installed. Disabling proxy support.", + proxy, + ) + else: + return httpcore.AsyncHTTPProxy(proxy_url=proxy, **opts) + + return httpcore.AsyncConnectionPool(**opts) + + def kill(self: "Self") -> "Optional[asyncio.Task[None]]": # type: ignore[override] + logger.debug("Killing HTTP transport") + self._worker.kill() + try: + # Return the pool cleanup task so caller can await it if needed + with mark_sentry_task_internal(): + return self.loop.create_task(self._pool.aclose()) # type: ignore[union-attr,unused-ignore] + except RuntimeError: + logger.warning("Event loop not running, aborting kill.") + return None + + +if not HTTP2_ENABLED: # Sorry, no Http2Transport for you class Http2Transport(HttpTransport): def __init__(self: "Self", options: "Dict[str, Any]") -> None: @@ -715,14 +1024,7 @@ class Http2Transport(BaseHttpTransport): # type: ignore def _get_header_value( self: "Self", response: "httpcore.Response", header: str ) -> "Optional[str]": - return next( - ( - val.decode("ascii") - for key, val in response.headers - if key.decode("ascii").lower() == header - ), - None, - ) + return _get_httpcore_header_value(response, header) def _request( self: "Self", @@ -735,72 +1037,23 @@ def _request( method, self._auth.get_api_url(endpoint_type), content=body, - headers=headers, # type: ignore - extensions={ - "timeout": { - "pool": self.TIMEOUT, - "connect": self.TIMEOUT, - "write": self.TIMEOUT, - "read": self.TIMEOUT, - } - }, + headers=headers, # type: ignore[arg-type,unused-ignore] + extensions=self._timeout_extensions, ) return response def _get_pool_options(self: "Self") -> "Dict[str, Any]": - options: "Dict[str, Any]" = { - "http2": self.parsed_dsn is not None - and self.parsed_dsn.scheme == "https", - "retries": 3, - } - - socket_options = ( - self.options["socket_options"] - if self.options["socket_options"] is not None - else [] - ) - - used_options = {(o[0], o[1]) for o in socket_options} - for default_option in KEEP_ALIVE_SOCKET_OPTIONS: - if (default_option[0], default_option[1]) not in used_options: - socket_options.append(default_option) - - options["socket_options"] = socket_options - - ssl_context = ssl.create_default_context() - ssl_context.load_verify_locations( - self.options["ca_certs"] # User-provided bundle from the SDK init - or os.environ.get("SSL_CERT_FILE") - or os.environ.get("REQUESTS_CA_BUNDLE") - or certifi.where() + return self._get_httpcore_pool_options( + http2=self.parsed_dsn is not None and self.parsed_dsn.scheme == "https" ) - cert_file = self.options["cert_file"] or os.environ.get("CLIENT_CERT_FILE") - key_file = self.options["key_file"] or os.environ.get("CLIENT_KEY_FILE") - if cert_file is not None: - ssl_context.load_cert_chain(cert_file, key_file) - - options["ssl_context"] = ssl_context - - return options def _make_pool( self: "Self", ) -> "Union[httpcore.SOCKSProxy, httpcore.HTTPProxy, httpcore.ConnectionPool]": if self.parsed_dsn is None: raise ValueError("Cannot create HTTP-based transport without valid DSN") - proxy = None - no_proxy = self._in_no_proxy(self.parsed_dsn) - - # try HTTPS first - https_proxy = self.options["https_proxy"] - if self.parsed_dsn.scheme == "https" and (https_proxy != ""): - proxy = https_proxy or (not no_proxy and getproxies().get("https")) - - # maybe fallback to HTTP proxy - http_proxy = self.options["http_proxy"] - if not proxy and (http_proxy != ""): - proxy = http_proxy or (not no_proxy and getproxies().get("http")) + proxy = self._resolve_proxy() opts = self._get_pool_options() if proxy: @@ -861,12 +1114,39 @@ def make_transport(options: "Dict[str, Any]") -> "Optional[Transport]": ref_transport = options["transport"] use_http2_transport = options.get("_experiments", {}).get("transport_http2", False) + use_async_transport = options.get("_experiments", {}).get("transport_async", False) + async_integration = any( + integration.__class__.__name__ == "AsyncioIntegration" + for integration in options.get("integrations") or [] + ) # By default, we use the http transport class transport_cls: "Type[Transport]" = ( Http2Transport if use_http2_transport else HttpTransport ) + if use_async_transport and ASYNC_TRANSPORT_AVAILABLE: + try: + asyncio.get_running_loop() + if async_integration: + if use_http2_transport: + logger.warning( + "HTTP/2 transport is not supported with async transport. " + "Ignoring transport_http2 experiment." + ) + transport_cls = AsyncHttpTransport + else: + logger.warning( + "You tried to use AsyncHttpTransport but the AsyncioIntegration is not enabled. Falling back to sync transport." + ) + except RuntimeError: + # No event loop running, fall back to sync transport + logger.warning("No event loop running, falling back to sync transport.") + elif use_async_transport: + logger.warning( + "You tried to use AsyncHttpTransport but don't have httpcore[asyncio] installed. Falling back to sync transport." + ) + if isinstance(ref_transport, Transport): return ref_transport elif isinstance(ref_transport, type) and issubclass(ref_transport, Transport): diff --git a/sentry_sdk/utils.py b/sentry_sdk/utils.py index 4dfd36d17c..be238e5142 100644 --- a/sentry_sdk/utils.py +++ b/sentry_sdk/utils.py @@ -1,4 +1,5 @@ import base64 +import contextvars import json import linecache import logging @@ -12,6 +13,7 @@ import threading import time from collections import namedtuple +from contextlib import contextmanager from datetime import datetime, timezone from decimal import Decimal from functools import partial, partialmethod, wraps @@ -44,6 +46,7 @@ Callable, ContextManager, Dict, + Generator, Iterator, List, NoReturn, @@ -81,6 +84,25 @@ _installed_modules = None +_is_sentry_internal_task = contextvars.ContextVar( + "is_sentry_internal_task", default=False +) + + +def is_internal_task() -> bool: + return _is_sentry_internal_task.get() + + +@contextmanager +def mark_sentry_task_internal() -> "Generator[None, None, None]": + """Context manager to mark a task as Sentry internal.""" + token = _is_sentry_internal_task.set(True) + try: + yield + finally: + _is_sentry_internal_task.reset(token) + + BASE64_ALPHABET = re.compile(r"^[a-zA-Z0-9/+=]*$") FALSY_ENV_VALUES = frozenset(("false", "f", "n", "no", "off", "0")) @@ -819,6 +841,8 @@ def exceptions_from_error( parent_id: int = 0, source: "Optional[str]" = None, full_stack: "Optional[list[dict[str, Any]]]" = None, + seen_exceptions: "Optional[list[BaseException]]" = None, + seen_exception_ids: "Optional[Set[int]]" = None, ) -> "Tuple[int, List[Dict[str, Any]]]": """ Creates the list of exceptions. @@ -826,8 +850,37 @@ def exceptions_from_error( See the Exception Interface documentation for more details: https://develop.sentry.dev/sdk/event-payloads/exception/ + + Args: + exception_id (int): + + Sequential counter for assigning ``mechanism.exception_id`` + to each processed exception. Is NOT the result of calling `id()` on the exception itself. + + parent_id (int): + + The ``mechanism.exception_id`` of the parent exception. + + Written into ``mechanism.parent_id`` in the event payload so Sentry can + reconstruct the exception tree. + + Not to be confused with ``seen_exception_ids``, which tracks Python ``id()`` + values for cycle detection. """ + if seen_exception_ids is None: + seen_exception_ids = set() + + if seen_exceptions is None: + seen_exceptions = [] + + if exc_value is not None and id(exc_value) in seen_exception_ids: + return (exception_id, []) + + if exc_value is not None: + seen_exceptions.append(exc_value) + seen_exception_ids.add(id(exc_value)) + parent = single_exception_from_error_tuple( exc_type=exc_type, exc_value=exc_value, @@ -866,6 +919,8 @@ def exceptions_from_error( exception_id=exception_id, source="__cause__", full_stack=full_stack, + seen_exceptions=seen_exceptions, + seen_exception_ids=seen_exception_ids, ) exceptions.extend(child_exceptions) @@ -888,6 +943,8 @@ def exceptions_from_error( exception_id=exception_id, source="__context__", full_stack=full_stack, + seen_exceptions=seen_exceptions, + seen_exception_ids=seen_exception_ids, ) exceptions.extend(child_exceptions) @@ -905,6 +962,8 @@ def exceptions_from_error( parent_id=parent_id, source="exceptions[%s]" % idx, full_stack=full_stack, + seen_exceptions=seen_exceptions, + seen_exception_ids=seen_exception_ids, ) exceptions.extend(child_exceptions) diff --git a/sentry_sdk/worker.py b/sentry_sdk/worker.py index 3d85a653d6..7931f9c027 100644 --- a/sentry_sdk/worker.py +++ b/sentry_sdk/worker.py @@ -1,9 +1,11 @@ +from abc import ABC, abstractmethod +import asyncio import os import threading from time import sleep, time from sentry_sdk._queue import Queue, FullError -from sentry_sdk.utils import logger +from sentry_sdk.utils import logger, mark_sentry_task_internal from sentry_sdk.consts import DEFAULT_QUEUE_SIZE from typing import TYPE_CHECKING @@ -17,7 +19,38 @@ _TERMINATOR = object() -class BackgroundWorker: +class Worker(ABC): + """Base class for all workers.""" + + @property + @abstractmethod + def is_alive(self) -> bool: + """Whether the worker is alive and running.""" + pass + + @abstractmethod + def kill(self) -> None: + """Kill the worker. It will not process any more events.""" + pass + + def flush( + self, timeout: float, callback: "Optional[Callable[[int, float], Any]]" = None + ) -> None: + """Flush the worker, blocking until done or timeout is reached.""" + return None + + @abstractmethod + def full(self) -> bool: + """Whether the worker's queue is full.""" + pass + + @abstractmethod + def submit(self, callback: "Callable[[], Any]") -> bool: + """Schedule a callback. Returns True if queued, False if full.""" + pass + + +class BackgroundWorker(Worker): def __init__(self, queue_size: int = DEFAULT_QUEUE_SIZE) -> None: self._queue: "Queue" = Queue(queue_size) self._lock = threading.Lock() @@ -107,7 +140,7 @@ def _wait_flush(self, timeout: float, callback: "Optional[Any]") -> None: pending = self._queue.qsize() + 1 logger.error("flush timed out, dropped %s events", pending) - def submit(self, callback: "Callable[[], None]") -> bool: + def submit(self, callback: "Callable[[], Any]") -> bool: self._ensure_thread() try: self._queue.put_nowait(callback) @@ -128,3 +161,151 @@ def _target(self) -> None: finally: self._queue.task_done() sleep(0) + + +class AsyncWorker(Worker): + def __init__(self, queue_size: int = DEFAULT_QUEUE_SIZE) -> None: + self._queue: "Optional[asyncio.Queue[Any]]" = None + self._queue_size = queue_size + self._task: "Optional[asyncio.Task[None]]" = None + # Event loop needs to remain in the same process + self._task_for_pid: "Optional[int]" = None + self._loop: "Optional[asyncio.AbstractEventLoop]" = None + # Track active callback tasks so they have a strong reference and can be cancelled on kill + self._active_tasks: "set[asyncio.Task[None]]" = set() + + @property + def is_alive(self) -> bool: + if self._task_for_pid != os.getpid(): + return False + if not self._task or not self._loop: + return False + return self._loop.is_running() and not self._task.done() + + def kill(self) -> None: + if self._task: + # Cancel the main consumer task to prevent duplicate consumers + self._task.cancel() + # Also cancel any active callback tasks + # Avoid modifying the set while cancelling tasks + tasks_to_cancel = set(self._active_tasks) + for task in tasks_to_cancel: + task.cancel() + self._active_tasks.clear() + self._loop = None + self._task = None + self._task_for_pid = None + + def start(self) -> None: + if not self.is_alive: + try: + self._loop = asyncio.get_running_loop() + # Always create a fresh queue on start to avoid stale items + self._queue = asyncio.Queue(maxsize=self._queue_size) + with mark_sentry_task_internal(): + self._task = self._loop.create_task(self._target()) + self._task_for_pid = os.getpid() + except RuntimeError: + # There is no event loop running + logger.warning("No event loop running, async worker not started") + self._loop = None + self._task = None + self._task_for_pid = None + + def full(self) -> bool: + if self._queue is None: + return True + return self._queue.full() + + def _ensure_task(self) -> None: + if not self.is_alive: + self.start() + + async def _wait_flush( + self, timeout: float, callback: "Optional[Any]" = None + ) -> None: + if not self._loop or not self._loop.is_running() or self._queue is None: + return + + initial_timeout = min(0.1, timeout) + + # Timeout on the join + try: + await asyncio.wait_for(self._queue.join(), timeout=initial_timeout) + except asyncio.TimeoutError: + pending = self._queue.qsize() + len(self._active_tasks) + logger.debug("%d event(s) pending on flush", pending) + if callback is not None: + callback(pending, timeout) + + try: + remaining_timeout = timeout - initial_timeout + await asyncio.wait_for(self._queue.join(), timeout=remaining_timeout) + except asyncio.TimeoutError: + pending = self._queue.qsize() + len(self._active_tasks) + logger.error("flush timed out, dropped %s events", pending) + + def flush( # type: ignore[override] + self, timeout: float, callback: "Optional[Any]" = None + ) -> "Optional[asyncio.Task[None]]": + if self.is_alive and timeout > 0.0 and self._loop and self._loop.is_running(): + with mark_sentry_task_internal(): + return self._loop.create_task(self._wait_flush(timeout, callback)) + return None + + def submit(self, callback: "Callable[[], Any]") -> bool: + self._ensure_task() + if self._queue is None: + return False + try: + self._queue.put_nowait(callback) + return True + except asyncio.QueueFull: + return False + + async def _target(self) -> None: + if self._queue is None: + return + try: + while True: + callback = await self._queue.get() + if callback is _TERMINATOR: + self._queue.task_done() + break + # Firing tasks instead of awaiting them allows for concurrent requests + with mark_sentry_task_internal(): + task = asyncio.create_task(self._process_callback(callback)) + # Create a strong reference to the task so it can be cancelled on kill + # and does not get garbage collected while running + self._active_tasks.add(task) + # Capture queue ref at dispatch time so done callbacks use the + # correct queue even if kill()/start() replace self._queue. + queue_ref = self._queue + task.add_done_callback(lambda t: self._on_task_complete(t, queue_ref)) + # Yield to let the event loop run other tasks + await asyncio.sleep(0) + except asyncio.CancelledError: + pass # Expected during kill() + + async def _process_callback(self, callback: "Callable[[], Any]") -> None: + # Callback is an async coroutine, need to await it + await callback() + + def _on_task_complete( + self, + task: "asyncio.Task[None]", + queue: "Optional[asyncio.Queue[Any]]" = None, + ) -> None: + try: + task.result() + except asyncio.CancelledError: + pass # Task was cancelled, expected during shutdown + except Exception: + logger.error("Failed processing job", exc_info=True) + finally: + # Mark the task as done and remove it from the active tasks set + # Use the queue reference captured at dispatch time, not self._queue, + # to avoid calling task_done() on a different queue after kill()/start(). + if queue is not None: + queue.task_done() + self._active_tasks.discard(task) diff --git a/setup.py b/setup.py index 86070b34ba..3942ee630e 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ def get_file_text(file_name): setup( name="sentry-sdk", - version="2.55.0", + version="2.58.0", author="Sentry Team and Contributors", author_email="hello@sentry.io", url="https://github.com/getsentry/sentry-python", @@ -36,7 +36,7 @@ def get_file_text(file_name): # PEP 561 package_data={"sentry_sdk": ["py.typed"]}, zip_safe=False, - license="MIT", + license_expression="MIT", python_requires=">=3.6", install_requires=[ "urllib3>=1.26.11", @@ -59,13 +59,14 @@ def get_file_text(file_name): "flask": ["flask>=0.11", "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"], + "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"], @@ -98,7 +99,6 @@ def get_file_text(file_name): "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", "Intended Audience :: Developers", - "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", diff --git a/tests/conftest.py b/tests/conftest.py index 7f76fc2aee..4e4943ba85 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,6 +7,7 @@ import brotli import gzip import io +from dataclasses import dataclass from threading import Thread from contextlib import contextmanager from http.server import BaseHTTPRequestHandler, HTTPServer @@ -48,6 +49,24 @@ from sentry_sdk.transport import Transport from sentry_sdk.utils import reraise +try: + import openai +except ImportError: + openai = None + + +try: + import anthropic +except ImportError: + anthropic = None + + +try: + import google +except ImportError: + google = None + + from tests import _warning_recorder, _warning_recorder_mgr from typing import TYPE_CHECKING @@ -314,6 +333,52 @@ def append_envelope(envelope): return inner +@dataclass +class UnwrappedItem: + type: str + payload: dict + + +@pytest.fixture +def capture_items(monkeypatch): + """ + Capture envelope payload, unfurling individual items. + + Makes it easier to work with both events and attribute-based telemetry in + one test. + """ + + def inner(*types): + telemetry = [] + test_client = sentry_sdk.get_client() + old_capture_envelope = test_client.transport.capture_envelope + + def append_envelope(envelope): + for item in envelope: + if types and item.type not in types: + continue + + if item.type in ("metric", "log", "span"): + for i in item.payload.json["items"]: + t = {k: v for k, v in i.items() if k != "attributes"} + t["attributes"] = { + k: v["value"] for k, v in i["attributes"].items() + } + telemetry.append(UnwrappedItem(type=item.type, payload=t)) + else: + telemetry.append( + UnwrappedItem(type=item.type, payload=item.payload.json) + ) + + return old_capture_envelope(envelope) + + monkeypatch.setattr(test_client.transport, "capture_envelope", append_envelope) + + return telemetry + + return inner + + @pytest.fixture def capture_record_lost_event_calls(monkeypatch): def inner(): @@ -1018,10 +1083,14 @@ async def inner(values): @pytest.fixture def server_side_event_chunks(): - def inner(events): + def inner(events, include_event_type=True): for event in events: payload = event.model_dump() - chunk = f"event: {payload['type']}\ndata: {json.dumps(payload)}\n\n" + chunk = ( + f"event: {payload['type']}\ndata: {json.dumps(payload)}\n\n" + if include_event_type + else f"data: {json.dumps(payload)}\n\n" + ) yield chunk.encode("utf-8") return inner @@ -1029,14 +1098,23 @@ def inner(events): @pytest.fixture def get_model_response(): - def inner(response_content, serialize_pydantic=False): + def inner(response_content, serialize_pydantic=False, request_headers=None): + if request_headers is None: + request_headers = {} + model_request = HttpxRequest( "POST", "/responses", + headers=request_headers, ) if serialize_pydantic: - response_content = json.dumps(response_content.model_dump()).encode("utf-8") + response_content = json.dumps( + response_content.model_dump( + by_alias=True, + exclude_none=True, + ) + ).encode("utf-8") response = HttpxResponse( 200, @@ -1049,6 +1127,331 @@ def inner(response_content, serialize_pydantic=False): return inner +@pytest.fixture +def get_rate_limit_model_response(): + def inner(request_headers=None): + if request_headers is None: + request_headers = {} + + model_request = HttpxRequest( + "POST", + "/responses", + headers=request_headers, + ) + + response = HttpxResponse( + 429, + request=model_request, + ) + + return response + + return inner + + +@pytest.fixture +def streaming_chat_completions_model_response(): + return [ + openai.types.chat.ChatCompletionChunk( + id="chatcmpl-test", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + openai.types.chat.chat_completion_chunk.Choice( + index=0, + delta=openai.types.chat.chat_completion_chunk.ChoiceDelta( + role="assistant" + ), + finish_reason=None, + ), + ], + ), + openai.types.chat.ChatCompletionChunk( + id="chatcmpl-test", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + openai.types.chat.chat_completion_chunk.Choice( + index=0, + delta=openai.types.chat.chat_completion_chunk.ChoiceDelta( + content="Tes" + ), + finish_reason=None, + ), + ], + ), + openai.types.chat.ChatCompletionChunk( + id="chatcmpl-test", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + openai.types.chat.chat_completion_chunk.Choice( + index=0, + delta=openai.types.chat.chat_completion_chunk.ChoiceDelta( + content="t r" + ), + finish_reason=None, + ), + ], + ), + openai.types.chat.ChatCompletionChunk( + id="chatcmpl-test", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + openai.types.chat.chat_completion_chunk.Choice( + index=0, + delta=openai.types.chat.chat_completion_chunk.ChoiceDelta( + content="esp" + ), + finish_reason=None, + ), + ], + ), + openai.types.chat.ChatCompletionChunk( + id="chatcmpl-test", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + openai.types.chat.chat_completion_chunk.Choice( + index=0, + delta=openai.types.chat.chat_completion_chunk.ChoiceDelta( + content="ons" + ), + finish_reason=None, + ), + ], + ), + openai.types.chat.ChatCompletionChunk( + id="chatcmpl-test", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + openai.types.chat.chat_completion_chunk.Choice( + index=0, + delta=openai.types.chat.chat_completion_chunk.ChoiceDelta( + content="e" + ), + finish_reason=None, + ), + ], + ), + openai.types.chat.ChatCompletionChunk( + id="chatcmpl-test", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + openai.types.chat.chat_completion_chunk.Choice( + index=0, + delta=openai.types.chat.chat_completion_chunk.ChoiceDelta(), + finish_reason="stop", + ), + ], + usage=openai.types.CompletionUsage( + prompt_tokens=10, + completion_tokens=20, + total_tokens=30, + ), + ), + ] + + +@pytest.fixture +def nonstreaming_chat_completions_model_response(): + return openai.types.chat.ChatCompletion( + id="chatcmpl-test", + choices=[ + openai.types.chat.chat_completion.Choice( + index=0, + finish_reason="stop", + message=openai.types.chat.ChatCompletionMessage( + role="assistant", content="Test response" + ), + ) + ], + created=1234567890, + model="gpt-3.5-turbo", + object="chat.completion", + usage=openai.types.CompletionUsage( + prompt_tokens=10, + completion_tokens=20, + total_tokens=30, + ), + ) + + +@pytest.fixture +def openai_embedding_model_response(): + return openai.types.CreateEmbeddingResponse( + data=[ + openai.types.Embedding( + embedding=[0.1, 0.2, 0.3], + index=0, + object="embedding", + ) + ], + model="text-embedding-ada-002", + object="list", + usage=openai.types.create_embedding_response.Usage( + prompt_tokens=5, + total_tokens=5, + ), + ) + + +@pytest.fixture +def nonstreaming_responses_model_response(): + return openai.types.responses.Response( + id="resp_123", + output=[ + openai.types.responses.ResponseOutputMessage( + id="msg_123", + type="message", + status="completed", + content=[ + openai.types.responses.ResponseOutputText( + text="Hello, how can I help you?", + type="output_text", + annotations=[], + ) + ], + role="assistant", + ) + ], + parallel_tool_calls=False, + tool_choice="none", + tools=[], + created_at=10000000, + model="gpt-4", + object="response", + usage=openai.types.responses.ResponseUsage( + input_tokens=10, + input_tokens_details=openai.types.responses.response_usage.InputTokensDetails( + cached_tokens=0, + ), + output_tokens=20, + output_tokens_details=openai.types.responses.response_usage.OutputTokensDetails( + reasoning_tokens=5, + ), + total_tokens=30, + ), + ) + + +@pytest.fixture +def nonstreaming_anthropic_model_response(): + return anthropic.types.Message( + id="msg_123", + type="message", + role="assistant", + model="claude-3-opus-20240229", + content=[ + anthropic.types.TextBlock( + type="text", + text="Hello, how can I help you?", + ) + ], + stop_reason="end_turn", + stop_sequence=None, + usage=anthropic.types.Usage( + input_tokens=10, + output_tokens=20, + ), + ) + + +@pytest.fixture +def nonstreaming_google_genai_model_response(): + return google.genai.types.GenerateContentResponse( + response_id="resp_123", + candidates=[ + google.genai.types.Candidate( + content=google.genai.types.Content( + role="model", + parts=[ + google.genai.types.Part( + text="Hello, how can I help you?", + ) + ], + ), + finish_reason="STOP", + ) + ], + model_version="gemini/gemini-pro", + usage_metadata=google.genai.types.GenerateContentResponseUsageMetadata( + prompt_token_count=10, + candidates_token_count=20, + total_token_count=30, + ), + ) + + +@pytest.fixture +def responses_tool_call_model_responses(): + def inner( + tool_name: str, + arguments: str, + response_model: str, + response_text: str, + response_ids: "Iterator[str]", + usages: "Iterator[openai.types.responses.ResponseUsage]", + ): + yield openai.types.responses.Response( + id=next(response_ids), + output=[ + openai.types.responses.ResponseFunctionToolCall( + id="call_123", + call_id="call_123", + name=tool_name, + type="function_call", + arguments=arguments, + ) + ], + parallel_tool_calls=False, + tool_choice="none", + tools=[], + created_at=10000000, + model=response_model, + object="response", + usage=next(usages), + ) + + yield openai.types.responses.Response( + id=next(response_ids), + output=[ + openai.types.responses.ResponseOutputMessage( + id="msg_final", + type="message", + status="completed", + content=[ + openai.types.responses.ResponseOutputText( + text=response_text, + type="output_text", + annotations=[], + ) + ], + role="assistant", + ) + ], + parallel_tool_calls=False, + tool_choice="none", + tools=[], + created_at=10000000, + model=response_model, + object="response", + usage=next(usages), + ) + + return inner + + class MockServerRequestHandler(BaseHTTPRequestHandler): def do_GET(self): # noqa: N802 # Process an HTTP GET request and return a response. diff --git a/tests/integrations/anthropic/test_anthropic.py b/tests/integrations/anthropic/test_anthropic.py index bd9a41e701..e86f7e1fa9 100644 --- a/tests/integrations/anthropic/test_anthropic.py +++ b/tests/integrations/anthropic/test_anthropic.py @@ -2204,7 +2204,6 @@ def test_span_status_error(sentry_init, capture_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" assert transaction["spans"][0]["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" assert transaction["spans"][0]["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" @@ -2230,7 +2229,6 @@ async def test_span_status_error_async(sentry_init, capture_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" assert transaction["spans"][0]["data"][SPANDATA.GEN_AI_SYSTEM] == "anthropic" assert transaction["spans"][0]["data"][SPANDATA.GEN_AI_OPERATION_NAME] == "chat" diff --git a/tests/integrations/asgi/test_asgi.py b/tests/integrations/asgi/test_asgi.py index ec2796c140..7f44c9d00a 100644 --- a/tests/integrations/asgi/test_asgi.py +++ b/tests/integrations/asgi/test_asgi.py @@ -164,55 +164,117 @@ def test_invalid_transaction_style(asgi3_app): @pytest.mark.asyncio +@pytest.mark.parametrize( + "span_streaming", + [True, False], +) async def test_capture_transaction( sentry_init, asgi3_app, capture_events, + capture_items, + span_streaming, ): - sentry_init(send_default_pii=True, traces_sample_rate=1.0) + sentry_init( + send_default_pii=True, + traces_sample_rate=1.0, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) app = SentryAsgiMiddleware(asgi3_app) async with TestClient(app) as client: - events = capture_events() + if span_streaming: + items = capture_items("span") + else: + events = capture_events() await client.get("/some_url?somevalue=123") - (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", - } + sentry_sdk.flush() + + if span_streaming: + assert len(items) == 1 + span = items[0].payload + + assert span["is_segment"] is True + assert span["name"] == "/some_url" + + assert span["attributes"]["sentry.span.source"] == "url" + assert span["attributes"]["sentry.op"] == "http.server" + + assert span["attributes"]["url.full"] == "http://localhost/some_url" + assert span["attributes"]["network.protocol.name"] == "http" + assert span["attributes"]["http.request.method"] == "GET" + assert span["attributes"]["http.query"] == "somevalue=123" + 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" + ) + + 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", + } @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) + sentry_init( + send_default_pii=True, + traces_sample_rate=1.0, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) + app = SentryAsgiMiddleware(asgi3_app_with_error) - events = capture_events() + if span_streaming: + items = capture_items("event", "span") + else: + events = capture_events() + with pytest.raises(ZeroDivisionError): async with TestClient(app) as client: await client.get("/some_url") - ( - error_event, - transaction_event, - ) = events + 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, transaction_event) = events assert error_event["transaction"] == "/some_url" assert error_event["transaction_info"] == {"source": "url"} @@ -222,45 +284,94 @@ 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" - 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"] + 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"] @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) + sentry_init( + traces_sample_rate=1.0, + _experiments={ + "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: - events = capture_events() + if span_streaming: + items = capture_items("event", "span") + else: + events = capture_events() await client.get("/") - msg_event, error_event, transaction_event = events + sentry_sdk.flush() - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] + if span_streaming: + msg_event, error_event, span = items - assert error_event["contexts"]["trace"] - assert "trace_id" in error_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 transaction_event["contexts"]["trace"] - assert "trace_id" in transaction_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 ( - error_event["contexts"]["trace"]["trace_id"] - == transaction_event["contexts"]["trace"]["trace_id"] - == msg_event["contexts"]["trace"]["trace_id"] - ) + 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 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"] + == msg_event["contexts"]["trace"]["trace_id"] + ) @pytest.mark.asyncio @@ -286,13 +397,24 @@ 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) + sentry_init( + traces_sample_rate=1.0, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) app = SentryAsgiMiddleware(asgi3_app_with_error_and_msg) trace_id = "582b43a4192642f0b136d5159a501701" @@ -300,23 +422,50 @@ async def test_trace_from_headers_if_performance_enabled( with pytest.raises(ZeroDivisionError): async with TestClient(app) as client: - events = capture_events() + if span_streaming: + items = capture_items("event", "span") + else: + events = capture_events() await client.get("/", headers={"sentry-trace": sentry_trace_header}) - msg_event, error_event, transaction_event = events + sentry_sdk.flush() - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] + if span_streaming: + msg_event, error_event, span = items - assert error_event["contexts"]["trace"] - assert "trace_id" in error_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 transaction_event["contexts"]["trace"] - assert "trace_id" in transaction_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 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.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 + + 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 @pytest.mark.asyncio @@ -348,10 +497,25 @@ async def test_trace_from_headers_if_performance_disabled( @pytest.mark.asyncio -async def test_websocket(sentry_init, asgi3_ws_app, capture_events, request): - sentry_init(send_default_pii=True, traces_sample_rate=1.0) - - events = capture_events() +@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, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) asgi3_ws_app = SentryAsgiMiddleware(asgi3_ws_app) @@ -359,21 +523,48 @@ async def test_websocket(sentry_init, asgi3_ws_app, capture_events, request): with pytest.raises(ValueError): client = TestClient(asgi3_ws_app) + if span_streaming: + items = capture_items("event", "span") + else: + events = capture_events() async with client.websocket_connect(request_url) as ws: await ws.receive_text() - msg_event, error_event, transaction_event = events + 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!" + + 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 span.type == "span" + span = span.payload + assert span["name"] == request_url + assert span["attributes"]["sentry.span.source"] == "url" + + else: + msg_event, error_event, transaction_event = events - assert msg_event["transaction"] == request_url - assert msg_event["transaction_info"] == {"source": "url"} - assert msg_event["message"] == "Some message to the world!" + 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" + (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 transaction_event["transaction"] == request_url + assert transaction_event["transaction_info"] == {"source": "url"} @pytest.mark.asyncio @@ -431,17 +622,29 @@ 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) + sentry_init( + send_default_pii=True, + traces_sample_rate=1.0, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) app = SentryAsgiMiddleware(asgi3_app, transaction_style=transaction_style) scope = { @@ -451,13 +654,26 @@ async def test_transaction_style( } async with TestClient(app, scope=scope) as client: - events = capture_events() + if span_streaming: + items = capture_items("span") + else: + events = capture_events() await client.get(url) - (transaction_event,) = events + sentry_sdk.flush() + + if span_streaming: + assert len(items) == 1 + span = items[0].payload + + assert span["name"] == expected_transaction + assert span["attributes"]["sentry.span.source"] == expected_source + + else: + (transaction_event,) = events - assert transaction_event["transaction"] == expected_transaction - assert transaction_event["transaction_info"] == {"source": expected_source} + assert transaction_event["transaction"] == expected_transaction + assert transaction_event["transaction_info"] == {"source": expected_source} def mock_asgi2_app(): @@ -622,6 +838,10 @@ def test_get_headers(): ), ], ) +@pytest.mark.parametrize( + "span_streaming", + [True, False], +) async def test_transaction_name( sentry_init, request_url, @@ -630,28 +850,47 @@ async def test_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, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, ) - envelopes = capture_envelopes() + if span_streaming: + items = capture_items("span") + else: + envelopes = capture_envelopes() app = SentryAsgiMiddleware(asgi3_app, transaction_style=transaction_style) async with TestClient(app) as client: await client.get(request_url) - (transaction_envelope,) = envelopes - transaction_event = transaction_envelope.get_transaction_event() + if span_streaming: + sentry_sdk.flush() - assert transaction_event["transaction"] == expected_transaction_name - assert ( - transaction_event["transaction_info"]["source"] == expected_transaction_source - ) + assert len(items) == 1 + span = items[0].payload + + assert span["name"] == expected_transaction_name + assert span["attributes"]["sentry.span.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 + ) @pytest.mark.asyncio @@ -672,6 +911,10 @@ async def test_transaction_name( ), ], ) +@pytest.mark.parametrize( + "span_streaming", + [True, False], +) async def test_transaction_name_in_traces_sampler( sentry_init, request_url, @@ -679,6 +922,7 @@ 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. @@ -686,17 +930,28 @@ async def test_transaction_name_in_traces_sampler( """ def dummy_traces_sampler(sampling_context): - assert ( - sampling_context["transaction_context"]["name"] == expected_transaction_name - ) - assert ( - sampling_context["transaction_context"]["source"] - == expected_transaction_source - ) + if span_streaming: + assert sampling_context["span_context"]["name"] == expected_transaction_name + assert ( + sampling_context["span_context"]["attributes"]["sentry.span.source"] + == expected_transaction_source + ) + else: + assert ( + sampling_context["transaction_context"]["name"] + == expected_transaction_name + ) + assert ( + sampling_context["transaction_context"]["source"] + == expected_transaction_source + ) sentry_init( traces_sampler=dummy_traces_sampler, traces_sample_rate=1.0, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, ) app = SentryAsgiMiddleware(asgi3_app, transaction_style=transaction_style) @@ -706,17 +961,44 @@ 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 + sentry_init, + asgi3_custom_transaction_app, + capture_events, + capture_items, + span_streaming, ): - sentry_init(traces_sample_rate=1.0) - events = capture_events() + sentry_init( + traces_sample_rate=1.0, + _experiments={ + "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() await client.get("/test") - (transaction_event,) = events - assert transaction_event["type"] == "transaction" - assert transaction_event["transaction"] == "foobar" - assert transaction_event["transaction_info"] == {"source": "custom"} + 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.span.source"] == "custom" + + else: + (transaction_event,) = events + assert transaction_event["type"] == "transaction" + assert transaction_event["transaction"] == "foobar" + assert transaction_event["transaction_info"] == {"source": "custom"} diff --git a/tests/integrations/asyncio/test_asyncio.py b/tests/integrations/asyncio/test_asyncio.py index b41aa244cb..d32849c7b5 100644 --- a/tests/integrations/asyncio/test_asyncio.py +++ b/tests/integrations/asyncio/test_asyncio.py @@ -1,7 +1,10 @@ import asyncio import inspect import sys -from unittest.mock import MagicMock, patch +from unittest.mock import MagicMock, Mock, patch + +if sys.version_info >= (3, 8): + from unittest.mock import AsyncMock import pytest @@ -24,6 +27,11 @@ ) +minimum_python_39 = pytest.mark.skipif( + sys.version_info < (3, 9), reason="Test requires Python >= 3.9" +) + + minimum_python_311 = pytest.mark.skipif( sys.version_info < (3, 11), reason="Asyncio task context parameter was introduced in Python 3.11", @@ -564,3 +572,112 @@ async def test_delayed_enable_integration_after_disabling(sentry_init, capture_e (transaction,) = events assert transaction["spans"] assert transaction["spans"][0]["origin"] == "auto.function.asyncio" + + +@minimum_python_39 +@pytest.mark.asyncio(loop_scope="module") +async def test_internal_tasks_not_wrapped(sentry_init, capture_events): + from sentry_sdk.utils import mark_sentry_task_internal + + sentry_init(integrations=[AsyncioIntegration()], traces_sample_rate=1.0) + events = capture_events() + + # Create a user task that should be wrapped + async def user_task(): + await asyncio.sleep(0.01) + return "user_result" + + # Create an internal task that should NOT be wrapped + async def internal_task(): + await asyncio.sleep(0.01) + return "internal_result" + + 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 + + assert user_result == "user_result" + assert internal_result == "internal_result" + + 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', [])]}" + ) + + +@minimum_python_38 +def test_loop_close_patching(sentry_init): + sentry_init(integrations=[AsyncioIntegration()]) + + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + try: + with patch("asyncio.get_running_loop", return_value=loop): + assert not hasattr(loop, "_sentry_flush_patched") + AsyncioIntegration.setup_once() + assert hasattr(loop, "_sentry_flush_patched") + assert loop._sentry_flush_patched is True + + finally: + if not loop.is_closed(): + loop.close() + + +@minimum_python_38 +def test_loop_close_flushes_async_transport(sentry_init): + from sentry_sdk.transport import ASYNC_TRANSPORT_AVAILABLE, AsyncHttpTransport + + if not ASYNC_TRANSPORT_AVAILABLE: + pytest.skip("httpcore[asyncio] not installed") + + sentry_init(integrations=[AsyncioIntegration()]) + + # Save the current event loop to restore it later + try: + original_loop = asyncio.get_event_loop() + except RuntimeError: + original_loop = None + + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + try: + with patch("asyncio.get_running_loop", return_value=loop): + AsyncioIntegration.setup_once() + + mock_client = Mock() + mock_transport = Mock(spec=AsyncHttpTransport) + mock_client.transport = mock_transport + mock_client.close_async = AsyncMock(return_value=None) + + with patch("sentry_sdk.get_client", return_value=mock_client): + loop.close() + + mock_client.close_async.assert_called_once() + mock_client.close_async.assert_awaited_once() + + finally: + if not loop.is_closed(): + loop.close() + if original_loop: + asyncio.set_event_loop(original_loop) diff --git a/tests/integrations/asyncpg/test_asyncpg.py b/tests/integrations/asyncpg/test_asyncpg.py index e23612c055..2dcce52070 100644 --- a/tests/integrations/asyncpg/test_asyncpg.py +++ b/tests/integrations/asyncpg/test_asyncpg.py @@ -49,6 +49,7 @@ def _get_db_name(): "db.name": PG_NAME, "db.system": "postgresql", "db.user": PG_USER, + "db.driver.name": "asyncpg", "server.address": PG_HOST, "server.port": PG_PORT, } @@ -463,10 +464,7 @@ async def test_connection_pool(sentry_init, capture_events) -> None: { "category": "query", "data": {}, - "message": "SELECT pg_advisory_unlock_all();\n" - "CLOSE ALL;\n" - "UNLISTEN *;\n" - "RESET ALL;", + "message": "SELECT pg_advisory_unlock_all(); CLOSE ALL; UNLISTEN *; RESET ALL;", "type": "default", }, { @@ -478,10 +476,7 @@ async def test_connection_pool(sentry_init, capture_events) -> None: { "category": "query", "data": {}, - "message": "SELECT pg_advisory_unlock_all();\n" - "CLOSE ALL;\n" - "UNLISTEN *;\n" - "RESET ALL;", + "message": "SELECT pg_advisory_unlock_all(); CLOSE ALL; UNLISTEN *; RESET ALL;", "type": "default", }, ] @@ -491,7 +486,7 @@ async def test_connection_pool(sentry_init, capture_events) -> None: async def test_query_source_disabled(sentry_init, capture_events): sentry_options = { "integrations": [AsyncPGIntegration()], - "enable_tracing": True, + "traces_sample_rate": 1.0, "enable_db_query_source": False, "db_query_source_threshold_ms": 0, } @@ -529,7 +524,7 @@ async def test_query_source_enabled( ): sentry_options = { "integrations": [AsyncPGIntegration()], - "enable_tracing": True, + "traces_sample_rate": 1.0, "db_query_source_threshold_ms": 0, } if enable_db_query_source is not None: @@ -565,7 +560,7 @@ async def test_query_source_enabled( async def test_query_source(sentry_init, capture_events): sentry_init( integrations=[AsyncPGIntegration()], - enable_tracing=True, + traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, ) @@ -615,7 +610,7 @@ async def test_query_source_with_module_in_search_path(sentry_init, capture_even """ sentry_init( integrations=[AsyncPGIntegration()], - enable_tracing=True, + traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, ) @@ -661,7 +656,7 @@ async def test_query_source_with_module_in_search_path(sentry_init, capture_even async def test_no_query_source_if_duration_too_short(sentry_init, capture_events): sentry_init( integrations=[AsyncPGIntegration()], - enable_tracing=True, + traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=100, ) @@ -706,7 +701,7 @@ def fake_record_sql_queries(*args, **kwargs): async def test_query_source_if_duration_over_threshold(sentry_init, capture_events): sentry_init( integrations=[AsyncPGIntegration()], - enable_tracing=True, + traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=100, ) @@ -786,3 +781,79 @@ async def test_span_origin(sentry_init, capture_events): for span in event["spans"]: assert span["origin"] == "auto.db.asyncpg" + + +@pytest.mark.asyncio +async def test_multiline_query_description_normalized(sentry_init, capture_events): + sentry_init( + integrations=[AsyncPGIntegration()], + traces_sample_rate=1.0, + ) + 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 +): + 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"): + conn: Connection = await connect(PG_CONNECTION_URI) + await conn.execute( + """ + SELECT + id, + name + FROM + users + """ + ) + await conn.close() + + (event,) = events + spans = [ + s + for s in event["spans"] + if s["op"] == "db" and "filtered" in s.get("description", "") + ] + + assert len(spans) == 1 + assert spans[0]["description"] == "filtered" diff --git a/tests/integrations/celery/test_celery.py b/tests/integrations/celery/test_celery.py index 42ae6ea14f..5d2d19c06a 100644 --- a/tests/integrations/celery/test_celery.py +++ b/tests/integrations/celery/test_celery.py @@ -606,7 +606,7 @@ def example_task(): def test_messaging_destination_name_default_exchange( mock_request, routing_key, init_celery, capture_events ): - celery_app = init_celery(enable_tracing=True) + celery_app = init_celery(traces_sample_rate=1.0) events = capture_events() mock_request.delivery_info = {"routing_key": routing_key, "exchange": ""} @@ -630,7 +630,7 @@ def test_messaging_destination_name_nondefault_exchange( that the routing key is the queue name. Other exchanges may not guarantee this behavior. """ - celery_app = init_celery(enable_tracing=True) + celery_app = init_celery(traces_sample_rate=1.0) events = capture_events() mock_request.delivery_info = {"routing_key": "celery", "exchange": "custom"} @@ -645,7 +645,7 @@ def task(): ... def test_messaging_id(init_celery, capture_events): - celery = init_celery(enable_tracing=True) + celery = init_celery(traces_sample_rate=1.0) events = capture_events() @celery.task @@ -659,7 +659,7 @@ def example_task(): ... def test_retry_count_zero(init_celery, capture_events): - celery = init_celery(enable_tracing=True) + celery = init_celery(traces_sample_rate=1.0) events = capture_events() @celery.task() @@ -676,7 +676,7 @@ def task(): ... def test_retry_count_nonzero(mock_request, init_celery, capture_events): mock_request.retries = 3 - celery = init_celery(enable_tracing=True) + celery = init_celery(traces_sample_rate=1.0) events = capture_events() @celery.task() @@ -691,7 +691,7 @@ def task(): ... @pytest.mark.parametrize("system", ("redis", "amqp")) def test_messaging_system(system, init_celery, capture_events): - celery = init_celery(enable_tracing=True) + celery = init_celery(traces_sample_rate=1.0) events = capture_events() # Does not need to be a real URL, since we use always eager @@ -716,7 +716,7 @@ def publish(*args, **kwargs): monkeypatch.setattr(kombu.messaging.Producer, "_publish", publish) - sentry_init(integrations=[CeleryIntegration()], enable_tracing=True) + sentry_init(integrations=[CeleryIntegration()], traces_sample_rate=1.0) celery = Celery(__name__, broker=f"{system}://example.com") # noqa: E231 events = capture_events() @@ -754,7 +754,7 @@ def task(): ... def tests_span_origin_consumer(init_celery, capture_events): - celery = init_celery(enable_tracing=True) + celery = init_celery(traces_sample_rate=1.0) celery.conf.broker_url = "redis://example.com" # noqa: E231 events = capture_events() @@ -778,7 +778,7 @@ def publish(*args, **kwargs): monkeypatch.setattr(kombu.messaging.Producer, "_publish", publish) - sentry_init(integrations=[CeleryIntegration()], enable_tracing=True) + sentry_init(integrations=[CeleryIntegration()], traces_sample_rate=1.0) celery = Celery(__name__, broker="redis://example.com") # noqa: E231 events = capture_events() @@ -807,7 +807,7 @@ def test_send_task_wrapped( capture_events, reset_integrations, ): - sentry_init(integrations=[CeleryIntegration()], enable_tracing=True) + sentry_init(integrations=[CeleryIntegration()], traces_sample_rate=1.0) celery = Celery(__name__, broker="redis://example.com") # noqa: E231 events = capture_events() diff --git a/tests/integrations/celery/test_update_celery_task_headers.py b/tests/integrations/celery/test_update_celery_task_headers.py index 705c00de58..950b13826c 100644 --- a/tests/integrations/celery/test_update_celery_task_headers.py +++ b/tests/integrations/celery/test_update_celery_task_headers.py @@ -71,7 +71,7 @@ def test_monitor_beat_tasks_with_headers(monitor_beat_tasks): def test_span_with_transaction(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) headers = {} monitor_beat_tasks = False @@ -91,7 +91,7 @@ def test_span_with_transaction(sentry_init): def test_span_with_transaction_custom_headers(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) headers = { "baggage": BAGGAGE_VALUE, "sentry-trace": SENTRY_TRACE_VALUE, diff --git a/tests/integrations/clickhouse_driver/test_clickhouse_driver.py b/tests/integrations/clickhouse_driver/test_clickhouse_driver.py index 635f9334c4..b501aa3531 100644 --- a/tests/integrations/clickhouse_driver/test_clickhouse_driver.py +++ b/tests/integrations/clickhouse_driver/test_clickhouse_driver.py @@ -42,6 +42,7 @@ def test_clickhouse_client_breadcrumbs(sentry_init, capture_events) -> None: "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -54,6 +55,7 @@ def test_clickhouse_client_breadcrumbs(sentry_init, capture_events) -> None: "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -66,6 +68,7 @@ def test_clickhouse_client_breadcrumbs(sentry_init, capture_events) -> None: "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -78,6 +81,7 @@ def test_clickhouse_client_breadcrumbs(sentry_init, capture_events) -> None: "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -90,6 +94,7 @@ def test_clickhouse_client_breadcrumbs(sentry_init, capture_events) -> None: "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -257,6 +262,7 @@ def test_clickhouse_client_spans( "description": "DROP TABLE IF EXISTS test", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -272,6 +278,7 @@ def test_clickhouse_client_spans( "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", @@ -287,6 +294,7 @@ def test_clickhouse_client_spans( "description": "INSERT INTO test (x) VALUES", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -302,6 +310,7 @@ def test_clickhouse_client_spans( "description": "INSERT INTO test (x) VALUES", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -317,6 +326,7 @@ def test_clickhouse_client_spans( "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", @@ -529,6 +539,7 @@ def test_clickhouse_dbapi_breadcrumbs(sentry_init, capture_events) -> None: "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -541,6 +552,7 @@ def test_clickhouse_dbapi_breadcrumbs(sentry_init, capture_events) -> None: "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -553,6 +565,7 @@ def test_clickhouse_dbapi_breadcrumbs(sentry_init, capture_events) -> None: "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -565,6 +578,7 @@ def test_clickhouse_dbapi_breadcrumbs(sentry_init, capture_events) -> None: "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -577,6 +591,7 @@ def test_clickhouse_dbapi_breadcrumbs(sentry_init, capture_events) -> None: "category": "query", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -737,6 +752,7 @@ def test_clickhouse_dbapi_spans(sentry_init, capture_events, capture_envelopes) "description": "DROP TABLE IF EXISTS test", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -752,6 +768,7 @@ def test_clickhouse_dbapi_spans(sentry_init, capture_events, capture_envelopes) "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", @@ -767,6 +784,7 @@ def test_clickhouse_dbapi_spans(sentry_init, capture_events, capture_envelopes) "description": "INSERT INTO test (x) VALUES", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -782,6 +800,7 @@ def test_clickhouse_dbapi_spans(sentry_init, capture_events, capture_envelopes) "description": "INSERT INTO test (x) VALUES", "data": { "db.system": "clickhouse", + "db.driver.name": "clickhouse-driver", "db.name": "", "db.user": "default", "server.address": "localhost", @@ -797,6 +816,7 @@ def test_clickhouse_dbapi_spans(sentry_init, capture_events, capture_envelopes) "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", diff --git a/tests/integrations/google_genai/test_google_genai.py b/tests/integrations/google_genai/test_google_genai.py index 68ae9d234f..6e91ba6634 100644 --- a/tests/integrations/google_genai/test_google_genai.py +++ b/tests/integrations/google_genai/test_google_genai.py @@ -373,7 +373,6 @@ def get_weather(location: str) -> str: 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_TYPE] == "function" assert ( tool_span["data"][SPANDATA.GEN_AI_TOOL_DESCRIPTION] == "Get the weather for a location" @@ -942,11 +941,9 @@ def test_google_genai_message_truncation( assert isinstance(parsed_messages, list) assert len(parsed_messages) == 1 assert parsed_messages[0]["role"] == "user" - assert small_content in parsed_messages[0]["content"] - assert ( - event["_meta"]["spans"]["0"]["data"]["gen_ai.request.messages"][""]["len"] == 2 - ) + # 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 @@ -1595,6 +1592,12 @@ def test_generate_content_with_function_response( mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) + # Conversation with the function call from the model + function_call = genai_types.FunctionCall( + name="get_weather", + args={"location": "Paris"}, + ) + # Conversation with function response (tool result) function_response = genai_types.FunctionResponse( id="call_123", name="get_weather", response={"output": "Sunny, 72F"} @@ -1603,6 +1606,9 @@ def test_generate_content_with_function_response( genai_types.Content( role="user", parts=[genai_types.Part(text="What's the weather in Paris?")] ), + genai_types.Content( + role="model", parts=[genai_types.Part(function_call=function_call)] + ), genai_types.Content( role="user", parts=[genai_types.Part(function_response=function_response)] ), @@ -1708,7 +1714,13 @@ def test_generate_content_with_part_object_directly( def test_generate_content_with_list_of_dicts( sentry_init, capture_events, mock_genai_client ): - """Test generate_content with list of dict format inputs.""" + """ + Test generate_content with list of dict format inputs. + + We only keep (and assert) the last dict in `content` because we've made popping the last message a form of + message truncation to keep the span size within limits. If we were following OTEL conventions, all 3 dicts + would be present. + """ sentry_init( integrations=[GoogleGenAIIntegration(include_prompts=True)], traces_sample_rate=1.0, @@ -1788,6 +1800,98 @@ def test_generate_content_with_dict_inline_data( assert messages[0]["content"][1]["content"] == BLOB_DATA_SUBSTITUTE +def test_generate_content_without_parts_property_inline_data( + sentry_init, capture_events, mock_genai_client +): + sentry_init( + integrations=[GoogleGenAIIntegration(include_prompts=True)], + traces_sample_rate=1.0, + send_default_pii=True, + ) + events = capture_events() + + mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) + + contents = [ + {"text": "What's in this image?"}, + {"inline_data": {"data": b"fake_binary_data", "mime_type": "image/gif"}}, + ] + + 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() + ) + + (event,) = events + invoke_span = event["spans"][0] + + messages = json.loads(invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + + assert len(messages) == 1 + + assert len(messages[0]["content"]) == 2 + assert messages[0]["role"] == "user" + assert messages[0]["content"][0] == { + "text": "What's in this image?", + "type": "text", + } + assert messages[0]["content"][1]["inline_data"] + + assert messages[0]["content"][1]["inline_data"]["data"] == BLOB_DATA_SUBSTITUTE + assert messages[0]["content"][1]["inline_data"]["mime_type"] == "image/gif" + + +def test_generate_content_without_parts_property_inline_data_and_binary_data_within_string( + sentry_init, capture_events, mock_genai_client +): + sentry_init( + integrations=[GoogleGenAIIntegration(include_prompts=True)], + traces_sample_rate=1.0, + send_default_pii=True, + ) + events = capture_events() + + mock_http_response = create_mock_http_response(EXAMPLE_API_RESPONSE_JSON) + + contents = [ + {"text": "What's in this image?"}, + { + "inline_data": { + "data": "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFUlEQVR42mP8z8BQz0AEYBxVSF+FABJADveWkH6oAAAAAElFTkSuQmCC", + "mime_type": "image/png", + } + }, + ] + + 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() + ) + + (event,) = events + invoke_span = event["spans"][0] + + messages = json.loads(invoke_span["data"][SPANDATA.GEN_AI_REQUEST_MESSAGES]) + assert len(messages) == 1 + assert messages[0]["role"] == "user" + + assert len(messages[0]["content"]) == 2 + assert messages[0]["content"][0] == { + "text": "What's in this image?", + "type": "text", + } + assert messages[0]["content"][1]["inline_data"] + + assert messages[0]["content"][1]["inline_data"]["data"] == BLOB_DATA_SUBSTITUTE + assert messages[0]["content"][1]["inline_data"]["mime_type"] == "image/png" + + # Tests for extract_contents_messages function def test_extract_contents_messages_none(): """Test extract_contents_messages with None input""" diff --git a/tests/integrations/graphene/test_graphene.py b/tests/integrations/graphene/test_graphene.py index 5d54bb49cb..63bc5de5d2 100644 --- a/tests/integrations/graphene/test_graphene.py +++ b/tests/integrations/graphene/test_graphene.py @@ -207,7 +207,7 @@ def graphql_server_sync(): def test_graphql_span_holds_query_information(sentry_init, capture_events): sentry_init( integrations=[GrapheneIntegration(), FlaskIntegration()], - enable_tracing=True, + traces_sample_rate=1.0, default_integrations=False, ) events = capture_events() diff --git a/tests/integrations/huggingface_hub/test_huggingface_hub.py b/tests/integrations/huggingface_hub/test_huggingface_hub.py index d17a7a31ef..9dd15ca4b5 100644 --- a/tests/integrations/huggingface_hub/test_huggingface_hub.py +++ b/tests/integrations/huggingface_hub/test_huggingface_hub.py @@ -1,15 +1,14 @@ +import re +from typing import TYPE_CHECKING from unittest import mock + import pytest -import re import responses - from huggingface_hub import InferenceClient import sentry_sdk -from sentry_sdk.utils import package_version from sentry_sdk.integrations.huggingface_hub import HuggingfaceHubIntegration - -from typing import TYPE_CHECKING +from sentry_sdk.utils import package_version try: from huggingface_hub.utils._errors import HfHubHTTPError @@ -507,12 +506,12 @@ def test_text_generation( assert span is not None - assert span["op"] == "gen_ai.generate_text" - assert span["description"] == "generate_text test-model" + 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": "generate_text", + "gen_ai.operation.name": "text_completion", "gen_ai.request.model": "test-model", "gen_ai.response.finish_reasons": "length", "gen_ai.response.streaming": False, @@ -576,12 +575,12 @@ def test_text_generation_streaming( assert span is not None - assert span["op"] == "gen_ai.generate_text" - assert span["description"] == "generate_text test-model" + 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": "generate_text", + "gen_ai.operation.name": "text_completion", "gen_ai.request.model": "test-model", "gen_ai.response.finish_reasons": "length", "gen_ai.response.streaming": True, @@ -834,8 +833,6 @@ def test_span_status_error( assert span["status"] == "internal_error" assert span["tags"]["status"] == "internal_error" - assert transaction["contexts"]["trace"]["status"] == "internal_error" - @pytest.mark.httpx_mock(assert_all_requests_were_expected=False) @pytest.mark.parametrize("send_default_pii", [True, False]) diff --git a/tests/integrations/langchain/test_langchain.py b/tests/integrations/langchain/test_langchain.py index 132da0a9a0..498a5d6f4a 100644 --- a/tests/integrations/langchain/test_langchain.py +++ b/tests/integrations/langchain/test_langchain.py @@ -9,9 +9,10 @@ try: # Langchain >= 0.2 - from langchain_openai import ChatOpenAI + from langchain_openai import ChatOpenAI, OpenAI except ImportError: # Langchain < 0.2 + from langchain_community.llms import OpenAI from langchain_community.chat_models import ChatOpenAI from langchain_core.callbacks import BaseCallbackManager, CallbackManagerForLLMRun @@ -22,6 +23,7 @@ import sentry_sdk from sentry_sdk import start_transaction +from sentry_sdk.utils import package_version from sentry_sdk.integrations.langchain import ( LangchainIntegration, SentryLangchainCallback, @@ -32,12 +34,39 @@ try: # langchain v1+ from langchain.tools import tool + from langchain.agents import create_agent from langchain_classic.agents import AgentExecutor, create_openai_tools_agent # type: ignore[import-not-found] except ImportError: # langchain str: return llm_type +def test_langchain_text_completion( + sentry_init, + capture_events, + get_model_response, +): + sentry_init( + integrations=[ + LangchainIntegration( + include_prompts=True, + ) + ], + traces_sample_rate=1.0, + send_default_pii=True, + ) + events = capture_events() + + model_response = get_model_response( + Completion( + id="completion-id", + object="text_completion", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + CompletionChoice( + index=0, + finish_reason="stop", + text="The capital of France is Paris.", + ) + ], + usage=CompletionUsage( + prompt_tokens=10, + completion_tokens=15, + total_tokens=25, + ), + ), + serialize_pydantic=True, + ) + + model = OpenAI( + model_name="gpt-3.5-turbo", + temperature=0.7, + max_tokens=100, + openai_api_key="badkey", + ) + + with patch.object( + model.client._client._client, + "send", + return_value=model_response, + ) as _: + with 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 + + 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.pipeline.name"] == "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 + + +@pytest.mark.skipif( + LANGCHAIN_VERSION < (1,), + reason="LangChain 1.0+ required (ONE AGENT refactor)", +) @pytest.mark.parametrize( - "send_default_pii, include_prompts, use_unknown_llm_type", + "send_default_pii, include_prompts", [ - (True, True, False), - (True, False, False), - (False, True, False), - (False, False, True), + (True, True), + (True, False), + (False, True), + (False, False), + ], +) +@pytest.mark.parametrize( + "system_instructions_content", + [ + "You are very powerful assistant, but don't know current events", + [ + {"type": "text", "text": "You are a helpful assistant."}, + {"type": "text", "text": "Be concise and clear."}, + ], + ], + ids=["string", "blocks"], +) +def test_langchain_create_agent( + sentry_init, + capture_events, + send_default_pii, + include_prompts, + system_instructions_content, + request, + get_model_response, + nonstreaming_responses_model_response, +): + sentry_init( + integrations=[ + LangchainIntegration( + include_prompts=include_prompts, + ) + ], + traces_sample_rate=1.0, + send_default_pii=send_default_pii, + ) + events = capture_events() + + model_response = get_model_response( + nonstreaming_responses_model_response, + serialize_pydantic=True, + request_headers={ + "X-Stainless-Raw-Response": "True", + }, + ) + + llm = ChatOpenAI( + model_name="gpt-3.5-turbo", + temperature=0, + openai_api_key="badkey", + use_responses_api=True, + ) + agent = create_agent( + model=llm, + tools=[get_word_length], + system_prompt=SystemMessage(content=system_instructions_content), + name="word_length_agent", + ) + + with patch.object( + llm.client._client._client, + "send", + return_value=model_response, + ) as _: + with 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.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 + + if send_default_pii and include_prompts: + assert ( + chat_spans[0]["data"][SPANDATA.GEN_AI_RESPONSE_TEXT] + == "Hello, how can I help you?" + ) + + param_id = request.node.callspec.id + if "string" in param_id: + assert [ + { + "type": "text", + "content": "You are very powerful assistant, but don't know current events", + } + ] == json.loads(chat_spans[0]["data"][SPANDATA.GEN_AI_SYSTEM_INSTRUCTIONS]) + else: + assert [ + { + "type": "text", + "content": "You are a helpful assistant.", + }, + { + "type": "text", + "content": "Be concise and clear.", + }, + ] == 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", {}) + + +@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), + ], +) +def test_tool_execution_span( + sentry_init, + capture_events, + send_default_pii, + include_prompts, + get_model_response, + responses_tool_call_model_responses, +): + sentry_init( + integrations=[ + LangchainIntegration( + include_prompts=include_prompts, + ) + ], + traces_sample_rate=1.0, + send_default_pii=send_default_pii, + ) + events = capture_events() + + responses = responses_tool_call_model_responses( + tool_name="get_word_length", + arguments='{"word": "eudca"}', + response_model="gpt-4-0613", + response_text="The word eudca has 5 letters.", + response_ids=iter(["resp_1", "resp_2"]), + usages=iter( + [ + ResponseUsage( + input_tokens=142, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + ), + output_tokens=50, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=0, + ), + total_tokens=192, + ), + ResponseUsage( + input_tokens=89, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + ), + output_tokens=28, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=0, + ), + total_tokens=117, + ), + ] + ), + ) + tool_response = get_model_response( + next(responses), + serialize_pydantic=True, + request_headers={ + "X-Stainless-Raw-Response": "True", + }, + ) + final_response = get_model_response( + next(responses), + serialize_pydantic=True, + request_headers={ + "X-Stainless-Raw-Response": "True", + }, + ) + + llm = ChatOpenAI( + model_name="gpt-4", + temperature=0, + openai_api_key="badkey", + use_responses_api=True, + ) + agent = create_agent( + model=llm, + tools=[get_word_length], + name="word_length_agent", + ) + + with patch.object( + llm.client._client._client, + "send", + side_effect=[tool_response, final_response], + ) as _: + with 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.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"]["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"]["gen_ai.system"] == "openai-chat" + + 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] + + # 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 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 + + +@pytest.mark.parametrize( + "send_default_pii, include_prompts", + [ + (True, True), + (True, False), + (False, True), + (False, False), ], ) @pytest.mark.parametrize( @@ -87,18 +486,16 @@ def _llm_type(self) -> str: ], ids=["string", "list", "blocks"], ) -def test_langchain_agent( +def test_langchain_openai_tools_agent( sentry_init, capture_events, send_default_pii, include_prompts, - use_unknown_llm_type, system_instructions_content, request, + get_model_response, + server_side_event_chunks, ): - global llm_type - llm_type = "acme-llm" if use_unknown_llm_type else "openai-chat" - sentry_init( integrations=[ LangchainIntegration( @@ -120,87 +517,173 @@ def test_langchain_agent( MessagesPlaceholder(variable_name="agent_scratchpad"), ] ) - global stream_result_mock - stream_result_mock = Mock( - side_effect=[ + + tool_response = get_model_response( + server_side_event_chunks( [ - ChatGenerationChunk( - type="ChatGenerationChunk", - message=AIMessageChunk( - content="", - additional_kwargs={ - "tool_calls": [ - { - "index": 0, - "id": "call_BbeyNhCKa6kYLYzrD40NGm3b", - "function": { - "arguments": "", - "name": "get_word_length", - }, - "type": "function", - } - ] - }, - ), + ChatCompletionChunk( + id="chatcmpl-turn-1", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + Choice( + index=0, + delta=ChoiceDelta(role="assistant"), + finish_reason=None, + ), + ], ), - ChatGenerationChunk( - type="ChatGenerationChunk", - message=AIMessageChunk( - content="", - additional_kwargs={ - "tool_calls": [ - { - "index": 0, - "id": None, - "function": { - "arguments": '{"word": "eudca"}', - "name": None, - }, - "type": None, - } - ] - }, - ), + ChatCompletionChunk( + id="chatcmpl-turn-1", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + Choice( + index=0, + delta=ChoiceDelta( + tool_calls=[ + ChoiceDeltaToolCall( + index=0, + id="call_BbeyNhCKa6kYLYzrD40NGm3b", + type="function", + function=ChoiceDeltaToolCallFunction( + name="get_word_length", + arguments="", + ), + ), + ], + ), + finish_reason=None, + ), + ], ), - ChatGenerationChunk( - type="ChatGenerationChunk", - message=AIMessageChunk( - content="5", - usage_metadata={ - "input_tokens": 142, - "output_tokens": 50, - "total_tokens": 192, - "input_token_details": {"audio": 0, "cache_read": 0}, - "output_token_details": {"audio": 0, "reasoning": 0}, - }, + ChatCompletionChunk( + id="chatcmpl-turn-1", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + Choice( + index=0, + delta=ChoiceDelta( + tool_calls=[ + ChoiceDeltaToolCall( + index=0, + function=ChoiceDeltaToolCallFunction( + arguments='{"word": "eudca"}', + ), + ), + ], + ), + finish_reason=None, + ), + ], + ), + ChatCompletionChunk( + id="chatcmpl-turn-1", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + Choice( + index=0, + delta=ChoiceDelta(content="5"), + finish_reason=None, + ), + ], + ), + ChatCompletionChunk( + id="chatcmpl-turn-1", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + Choice( + index=0, + delta=ChoiceDelta(), + finish_reason="function_call", + ), + ], + ), + ChatCompletionChunk( + id="chatcmpl-turn-1", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[], + usage=CompletionUsage( + prompt_tokens=142, + completion_tokens=50, + total_tokens=192, ), - generation_info={"finish_reason": "function_call"}, ), ], + include_event_type=False, + ) + ) + + final_response = get_model_response( + server_side_event_chunks( [ - ChatGenerationChunk( - text="The word eudca has 5 letters.", - type="ChatGenerationChunk", - message=AIMessageChunk( - content="The word eudca has 5 letters.", - usage_metadata={ - "input_tokens": 89, - "output_tokens": 28, - "total_tokens": 117, - "input_token_details": {"audio": 0, "cache_read": 0}, - "output_token_details": {"audio": 0, "reasoning": 0}, - }, - ), + ChatCompletionChunk( + id="chatcmpl-turn-2", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + Choice( + index=0, + delta=ChoiceDelta(role="assistant"), + finish_reason=None, + ), + ], ), - ChatGenerationChunk( - type="ChatGenerationChunk", - generation_info={"finish_reason": "stop"}, - message=AIMessageChunk(content=""), + ChatCompletionChunk( + id="chatcmpl-turn-2", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + Choice( + index=0, + delta=ChoiceDelta(content="The word eudca has 5 letters."), + finish_reason=None, + ), + ], + ), + ChatCompletionChunk( + id="chatcmpl-turn-2", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[ + Choice( + index=0, + delta=ChoiceDelta(), + finish_reason="stop", + ), + ], + ), + ChatCompletionChunk( + id="chatcmpl-turn-2", + object="chat.completion.chunk", + created=10000000, + model="gpt-3.5-turbo", + choices=[], + usage=CompletionUsage( + prompt_tokens=89, + completion_tokens=28, + total_tokens=117, + ), ), ], - ] + include_event_type=False, + ) ) - llm = MockOpenAI( + + llm = ChatOpenAI( model_name="gpt-3.5-turbo", temperature=0, openai_api_key="badkey", @@ -209,16 +692,29 @@ def test_langchain_agent( agent_executor = AgentExecutor(agent=agent, tools=[get_word_length], verbose=True) - with 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], + ) as _: + with 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 = 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" + # 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 @@ -305,15 +801,17 @@ def test_langchain_agent( # Verify that available tools are always recorded regardless of PII settings for chat_span in chat_spans: - span_data = chat_span.get("data", {}) - if SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS in span_data: - tools_data = span_data[SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] - assert tools_data is not None, ( - "Available tools should always be recorded regardless of PII settings" - ) + 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 def test_langchain_error(sentry_init, capture_events): + global llm_type + llm_type = "acme-llm" + sentry_init( integrations=[LangchainIntegration(include_prompts=True)], traces_sample_rate=1.0, @@ -393,122 +891,6 @@ def test_span_status_error(sentry_init, capture_events): assert transaction["contexts"]["trace"]["status"] == "internal_error" -def test_span_origin(sentry_init, capture_events): - sentry_init( - integrations=[LangchainIntegration()], - traces_sample_rate=1.0, - ) - events = capture_events() - - prompt = ChatPromptTemplate.from_messages( - [ - ( - "system", - "You are very powerful assistant, but don't know current events", - ), - ("user", "{input}"), - MessagesPlaceholder(variable_name="agent_scratchpad"), - ] - ) - global stream_result_mock - stream_result_mock = Mock( - side_effect=[ - [ - ChatGenerationChunk( - type="ChatGenerationChunk", - message=AIMessageChunk( - content="", - additional_kwargs={ - "tool_calls": [ - { - "index": 0, - "id": "call_BbeyNhCKa6kYLYzrD40NGm3b", - "function": { - "arguments": "", - "name": "get_word_length", - }, - "type": "function", - } - ] - }, - ), - ), - ChatGenerationChunk( - type="ChatGenerationChunk", - message=AIMessageChunk( - content="", - additional_kwargs={ - "tool_calls": [ - { - "index": 0, - "id": None, - "function": { - "arguments": '{"word": "eudca"}', - "name": None, - }, - "type": None, - } - ] - }, - ), - ), - ChatGenerationChunk( - type="ChatGenerationChunk", - message=AIMessageChunk( - content="5", - usage_metadata={ - "input_tokens": 142, - "output_tokens": 50, - "total_tokens": 192, - "input_token_details": {"audio": 0, "cache_read": 0}, - "output_token_details": {"audio": 0, "reasoning": 0}, - }, - ), - generation_info={"finish_reason": "function_call"}, - ), - ], - [ - ChatGenerationChunk( - text="The word eudca has 5 letters.", - type="ChatGenerationChunk", - message=AIMessageChunk( - content="The word eudca has 5 letters.", - usage_metadata={ - "input_tokens": 89, - "output_tokens": 28, - "total_tokens": 117, - "input_token_details": {"audio": 0, "cache_read": 0}, - "output_token_details": {"audio": 0, "reasoning": 0}, - }, - ), - ), - ChatGenerationChunk( - type="ChatGenerationChunk", - generation_info={"finish_reason": "stop"}, - message=AIMessageChunk(content=""), - ), - ], - ] - ) - 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 start_transaction(): - list(agent_executor.stream({"input": "How many letters in the word eudca"})) - - (event,) = events - - assert event["contexts"]["trace"]["origin"] == "manual" - for span in event["spans"]: - assert span["origin"] == "auto.ai.langchain" - - def test_manual_callback_no_duplication(sentry_init): """ Test that when a user manually provides a SentryLangchainCallback, @@ -718,155 +1100,6 @@ def test_langchain_callback_list_existing_callback(sentry_init): assert handler is sentry_callback -def test_tools_integration_in_spans(sentry_init, capture_events): - """Test that tools are properly set on spans in actual LangChain integration.""" - global llm_type - llm_type = "openai-chat" - - sentry_init( - integrations=[LangchainIntegration(include_prompts=False)], - traces_sample_rate=1.0, - ) - events = capture_events() - - prompt = ChatPromptTemplate.from_messages( - [ - ("system", "You are a helpful assistant"), - ("user", "{input}"), - MessagesPlaceholder(variable_name="agent_scratchpad"), - ] - ) - - global stream_result_mock - stream_result_mock = Mock( - side_effect=[ - [ - ChatGenerationChunk( - type="ChatGenerationChunk", - message=AIMessageChunk(content="Simple response"), - ), - ] - ] - ) - - 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 start_transaction(): - list(agent_executor.stream({"input": "Hello"})) - - # Check that events were captured and contain tools data - if events: - tx = events[0] - spans = tx.get("spans", []) - - # Look for spans that should have tools data - tools_found = False - for span in spans: - span_data = span.get("data", {}) - if SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS in span_data: - tools_found = True - tools_data = span_data[SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS] - # Verify tools are in the expected format - assert isinstance(tools_data, (str, list)) # Could be serialized - if isinstance(tools_data, str): - # If serialized as string, should contain tool name - assert "get_word_length" in tools_data - else: - # If still a list, verify structure - assert len(tools_data) >= 1 - names = [ - tool.get("name") - for tool in tools_data - if isinstance(tool, dict) - ] - assert "get_word_length" in names - - # Ensure we found at least one span with tools data - assert tools_found, "No spans found with tools data" - - -def test_langchain_integration_with_langchain_core_only(sentry_init, capture_events): - """Test that the langchain integration works when langchain.agents.AgentExecutor - is not available or langchain is not installed, but langchain-core is. - """ - - from langchain_core.outputs import LLMResult, Generation - - with patch("sentry_sdk.integrations.langchain.AgentExecutor", None): - from sentry_sdk.integrations.langchain import ( - LangchainIntegration, - SentryLangchainCallback, - ) - - sentry_init( - integrations=[LangchainIntegration(include_prompts=True)], - traces_sample_rate=1.0, - send_default_pii=True, - ) - events = capture_events() - - try: - LangchainIntegration.setup_once() - except Exception as e: - pytest.fail(f"setup_once() failed when AgentExecutor is None: {e}") - - 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"} - prompts = ["What is the capital of France?"] - - with start_transaction(): - callback.on_llm_start( - serialized=serialized, - prompts=prompts, - run_id=run_id, - invocation_params={ - "temperature": 0.7, - "max_tokens": 100, - "model": "gpt-3.5-turbo", - }, - ) - - response = LLMResult( - generations=[[Generation(text="The capital of France is Paris.")]], - 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.pipeline" - ] - assert len(llm_spans) > 0 - - llm_span = llm_spans[0] - assert llm_span["description"] == "Langchain LLM call" - 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 - - def test_langchain_message_role_mapping(sentry_init, capture_events): """Test that message roles are properly normalized in langchain integration.""" global llm_type @@ -1038,6 +1271,7 @@ def test_langchain_message_truncation(sentry_init, capture_events): serialized=serialized, prompts=prompts, run_id=run_id, + name="my_pipeline", invocation_params={ "temperature": 0.7, "max_tokens": 100, @@ -1062,13 +1296,17 @@ def test_langchain_message_truncation(sentry_init, capture_events): assert tx["type"] == "transaction" llm_spans = [ - span for span in tx.get("spans", []) if span.get("op") == "gen_ai.pipeline" + 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 SPANDATA.GEN_AI_REQUEST_MESSAGES in llm_span["data"] + assert llm_span["data"]["gen_ai.operation.name"] == "text_completion" + assert llm_span["data"][SPANDATA.GEN_AI_PIPELINE_NAME] == "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) @@ -1776,11 +2014,14 @@ def test_langchain_response_model_extraction( assert tx["type"] == "transaction" llm_spans = [ - span for span in tx.get("spans", []) if span.get("op") == "gen_ai.pipeline" + 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" if expected_model is not None: assert SPANDATA.GEN_AI_RESPONSE_MODEL in llm_span["data"] @@ -2000,6 +2241,96 @@ def test_transform_google_file_data(self): } +@pytest.mark.parametrize( + "ai_type,expected_system", + [ + # Real LangChain _type values (from _llm_type properties) + # OpenAI + ("openai-chat", "openai-chat"), + ("openai", "openai"), + # Azure OpenAI + ("azure-openai-chat", "azure-openai-chat"), + ("azure", "azure"), + # Anthropic + ("anthropic-chat", "anthropic-chat"), + # Google + ("vertexai", "vertexai"), + ("chat-google-generative-ai", "chat-google-generative-ai"), + ("google_gemini", "google_gemini"), + # AWS Bedrock + ("amazon_bedrock_chat", "amazon_bedrock_chat"), + ("amazon_bedrock", "amazon_bedrock"), + # Cohere + ("cohere-chat", "cohere-chat"), + # Ollama + ("chat-ollama", "chat-ollama"), + ("ollama-llm", "ollama-llm"), + # Mistral + ("mistralai-chat", "mistralai-chat"), + # Fireworks + ("fireworks-chat", "fireworks-chat"), + ("fireworks", "fireworks"), + # HuggingFace + ("huggingface-chat-wrapper", "huggingface-chat-wrapper"), + # Groq + ("groq-chat", "groq-chat"), + # NVIDIA + ("chat-nvidia-ai-playground", "chat-nvidia-ai-playground"), + # xAI + ("xai-chat", "xai-chat"), + # DeepSeek + ("chat-deepseek", "chat-deepseek"), + # Edge cases + ("", None), + (None, None), + ], +) +def test_langchain_ai_system_detection( + sentry_init, capture_events, ai_type, expected_system +): + sentry_init( + integrations=[LangchainIntegration()], + traces_sample_rate=1.0, + ) + events = capture_events() + + callback = SentryLangchainCallback(max_span_map_size=100, include_prompts=True) + + run_id = "test-ai-system-uuid" + serialized = {"_type": ai_type} if ai_type is not None else {} + prompts = ["Test prompt"] + + 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", {}) + + class TestTransformLangchainMessageContent: """Tests for _transform_langchain_message_content function.""" diff --git a/tests/integrations/litellm/test_litellm.py b/tests/integrations/litellm/test_litellm.py index 9022093fa3..a8df5891ce 100644 --- a/tests/integrations/litellm/test_litellm.py +++ b/tests/integrations/litellm/test_litellm.py @@ -2,6 +2,7 @@ import json import pytest import time +import asyncio from unittest import mock from datetime import datetime @@ -31,10 +32,34 @@ async def __call__(self, *args, **kwargs): ) from sentry_sdk.utils import package_version +from openai import OpenAI, AsyncOpenAI + +from concurrent.futures import ThreadPoolExecutor + +import litellm.utils as litellm_utils +from litellm.litellm_core_utils import streaming_handler +from litellm.litellm_core_utils import thread_pool_executor +from litellm.litellm_core_utils import litellm_logging +from litellm.litellm_core_utils.logging_worker import GLOBAL_LOGGING_WORKER +from litellm.llms.custom_httpx.http_handler import HTTPHandler, AsyncHTTPHandler + LITELLM_VERSION = package_version("litellm") +def _reset_litellm_executor(): + thread_pool_executor.executor = ThreadPoolExecutor(max_workers=100) + litellm_utils.executor = thread_pool_executor.executor + streaming_handler.executor = thread_pool_executor.executor + litellm_logging.executor = thread_pool_executor.executor + + +@pytest.fixture() +def reset_litellm_executor(): + yield + _reset_litellm_executor() + + @pytest.fixture def clear_litellm_cache(): """ @@ -105,38 +130,89 @@ def __init__( self.created = 1234567890 -class MockEmbeddingData: - def __init__(self, embedding=None): - self.embedding = embedding or [0.1, 0.2, 0.3] - self.index = 0 - self.object = "embedding" +@pytest.mark.parametrize( + "send_default_pii, include_prompts", + [ + (True, True), + (True, False), + (False, True), + (False, False), + ], +) +def test_nonstreaming_chat_completion( + reset_litellm_executor, + sentry_init, + capture_events, + send_default_pii, + include_prompts, + get_model_response, + nonstreaming_chat_completions_model_response, +): + sentry_init( + integrations=[LiteLLMIntegration(include_prompts=include_prompts)], + traces_sample_rate=1.0, + send_default_pii=send_default_pii, + ) + events = capture_events() + messages = [{"role": "user", "content": "Hello!"}] -class MockEmbeddingResponse: - def __init__(self, model="text-embedding-ada-002", data=None, usage=None): - self.model = model - self.data = data or [MockEmbeddingData()] - self.usage = usage or MockUsage( - prompt_tokens=5, completion_tokens=0, total_tokens=5 - ) - self.object = "list" + client = OpenAI(api_key="test-key") - def model_dump(self): - return { - "model": self.model, - "data": [ - {"embedding": d.embedding, "index": d.index, "object": d.object} - for d in self.data - ], - "usage": { - "prompt_tokens": self.usage.prompt_tokens, - "completion_tokens": self.usage.completion_tokens, - "total_tokens": self.usage.total_tokens, - }, - "object": self.object, - } + model_response = get_model_response( + nonstreaming_chat_completions_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with start_transaction(name="litellm test"): + litellm.completion( + model="gpt-3.5-turbo", + messages=messages, + client=client, + ) + + litellm_utils.executor.shutdown(wait=True) + + assert len(events) == 1 + (event,) = events + + 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.asyncio(loop_scope="session") @pytest.mark.parametrize( "send_default_pii, include_prompts", [ @@ -146,8 +222,13 @@ def model_dump(self): (False, False), ], ) -def test_nonstreaming_chat_completion( - sentry_init, capture_events, send_default_pii, include_prompts +async def test_async_nonstreaming_chat_completion( + sentry_init, + capture_events, + send_default_pii, + include_prompts, + get_model_response, + nonstreaming_chat_completions_model_response, ): sentry_init( integrations=[LiteLLMIntegration(include_prompts=include_prompts)], @@ -157,22 +238,29 @@ def test_nonstreaming_chat_completion( events = capture_events() messages = [{"role": "user", "content": "Hello!"}] - mock_response = MockCompletionResponse() - with start_transaction(name="litellm test"): - # Simulate what litellm does: call input callback, then success callback - kwargs = { - "model": "gpt-3.5-turbo", - "messages": messages, - } + client = AsyncOpenAI(api_key="test-key") - _input_callback(kwargs) - _success_callback( - kwargs, - mock_response, - datetime.now(), - datetime.now(), - ) + model_response = get_model_response( + nonstreaming_chat_completions_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with 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) assert len(events) == 1 (event,) = events @@ -180,8 +268,13 @@ def test_nonstreaming_chat_completion( assert event["type"] == "transaction" assert event["transaction"] == "litellm test" - assert len(event["spans"]) == 1 - (span,) = event["spans"] + 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" @@ -212,7 +305,14 @@ def test_nonstreaming_chat_completion( ], ) def test_streaming_chat_completion( - sentry_init, capture_events, send_default_pii, include_prompts + reset_litellm_executor, + sentry_init, + capture_events, + send_default_pii, + include_prompts, + get_model_response, + server_side_event_chunks, + streaming_chat_completions_model_response, ): sentry_init( integrations=[LiteLLMIntegration(include_prompts=include_prompts)], @@ -222,35 +322,132 @@ def test_streaming_chat_completion( events = capture_events() messages = [{"role": "user", "content": "Hello!"}] - mock_response = MockCompletionResponse() - with start_transaction(name="litellm test"): - kwargs = { - "model": "gpt-3.5-turbo", - "messages": messages, - "stream": True, - } + client = OpenAI(api_key="test-key") - _input_callback(kwargs) - _success_callback( - kwargs, - mock_response, - datetime.now(), - datetime.now(), - ) + model_response = get_model_response( + server_side_event_chunks( + streaming_chat_completions_model_response, + include_event_type=False, + ), + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with 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" - assert len(event["spans"]) == 1 - (span,) = event["spans"] + 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["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True + + +@pytest.mark.asyncio(loop_scope="session") +@pytest.mark.parametrize( + "send_default_pii, include_prompts", + [ + (True, True), + (True, False), + (False, True), + (False, False), + ], +) +async def test_async_streaming_chat_completion( + sentry_init, + capture_events, + send_default_pii, + include_prompts, + get_model_response, + async_iterator, + server_side_event_chunks, + streaming_chat_completions_model_response, +): + sentry_init( + integrations=[LiteLLMIntegration(include_prompts=include_prompts)], + traces_sample_rate=1.0, + send_default_pii=send_default_pii, + ) + events = capture_events() + + messages = [{"role": "user", "content": "Hello!"}] + + client = AsyncOpenAI(api_key="test-key") + + model_response = get_model_response( + async_iterator( + server_side_event_chunks( + streaming_chat_completions_model_response, + include_event_type=False, + ), + ), + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with 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] assert span["op"] == OP.GEN_AI_CHAT assert span["data"][SPANDATA.GEN_AI_RESPONSE_STREAMING] is True -def test_embeddings_create(sentry_init, capture_events, clear_litellm_cache): +def test_embeddings_create( + sentry_init, + capture_events, + get_model_response, + openai_embedding_model_response, + clear_litellm_cache, +): """ Test that litellm.embedding() calls are properly instrumented. @@ -264,20 +461,24 @@ def test_embeddings_create(sentry_init, capture_events, clear_litellm_cache): ) events = capture_events() - mock_response = MockEmbeddingResponse() + client = OpenAI(api_key="test-key") - # Mock within the test to ensure proper ordering with cache clearing - with mock.patch( - "litellm.openai_chat_completions.make_sync_openai_embedding_request" - ) as mock_http: - # The function returns (headers, response) - mock_http.return_value = ({}, mock_response) + model_response = get_model_response( + openai_embedding_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + 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!", - api_key="test-key", # Provide a fake API key to avoid authentication errors + client=client, ) # Allow time for callbacks to complete (they may run in separate threads) time.sleep(0.1) @@ -288,8 +489,81 @@ def test_embeddings_create(sentry_init, capture_events, clear_litellm_cache): (event,) = events assert event["type"] == "transaction" - assert len(event["spans"]) == 1 - (span,) = event["spans"] + 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.asyncio(loop_scope="session") +async def test_async_embeddings_create( + sentry_init, + capture_events, + get_model_response, + openai_embedding_model_response, + clear_litellm_cache, +): + """ + Test that litellm.embedding() calls are properly instrumented. + + This test calls the actual litellm.embedding() function (not just callbacks) + to ensure proper integration testing. + """ + sentry_init( + integrations=[LiteLLMIntegration(include_prompts=True)], + traces_sample_rate=1.0, + send_default_pii=True, + ) + events = capture_events() + + client = AsyncOpenAI(api_key="test-key") + + model_response = get_model_response( + openai_embedding_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + 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" @@ -302,7 +576,11 @@ def test_embeddings_create(sentry_init, capture_events, clear_litellm_cache): def test_embeddings_create_with_list_input( - sentry_init, capture_events, clear_litellm_cache + sentry_init, + capture_events, + get_model_response, + openai_embedding_model_response, + clear_litellm_cache, ): """Test embedding with list input.""" sentry_init( @@ -312,20 +590,24 @@ def test_embeddings_create_with_list_input( ) events = capture_events() - mock_response = MockEmbeddingResponse() + client = OpenAI(api_key="test-key") - # Mock within the test to ensure proper ordering with cache clearing - with mock.patch( - "litellm.openai_chat_completions.make_sync_openai_embedding_request" - ) as mock_http: - # The function returns (headers, response) - mock_http.return_value = ({}, mock_response) + model_response = get_model_response( + openai_embedding_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + 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"], - api_key="test-key", # Provide a fake API key to avoid authentication errors + client=client, ) # Allow time for callbacks to complete (they may run in separate threads) time.sleep(0.1) @@ -336,8 +618,77 @@ def test_embeddings_create_with_list_input( (event,) = events assert event["type"] == "transaction" - assert len(event["spans"]) == 1 - (span,) = event["spans"] + 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.asyncio(loop_scope="session") +async def test_async_embeddings_create_with_list_input( + sentry_init, + capture_events, + get_model_response, + openai_embedding_model_response, + clear_litellm_cache, +): + """Test embedding with list input.""" + sentry_init( + integrations=[LiteLLMIntegration(include_prompts=True)], + traces_sample_rate=1.0, + send_default_pii=True, + ) + events = capture_events() + + client = AsyncOpenAI(api_key="test-key") + + model_response = get_model_response( + openai_embedding_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + 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" @@ -350,7 +701,13 @@ def test_embeddings_create_with_list_input( ] -def test_embeddings_no_pii(sentry_init, capture_events, clear_litellm_cache): +def test_embeddings_no_pii( + sentry_init, + capture_events, + get_model_response, + openai_embedding_model_response, + clear_litellm_cache, +): """Test that PII is not captured when disabled.""" sentry_init( integrations=[LiteLLMIntegration(include_prompts=True)], @@ -359,20 +716,24 @@ def test_embeddings_no_pii(sentry_init, capture_events, clear_litellm_cache): ) events = capture_events() - mock_response = MockEmbeddingResponse() + client = OpenAI(api_key="test-key") - # Mock within the test to ensure proper ordering with cache clearing - with mock.patch( - "litellm.openai_chat_completions.make_sync_openai_embedding_request" - ) as mock_http: - # The function returns (headers, response) - mock_http.return_value = ({}, mock_response) + model_response = get_model_response( + openai_embedding_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + 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!", - api_key="test-key", # Provide a fake API key to avoid authentication errors + client=client, ) # Allow time for callbacks to complete (they may run in separate threads) time.sleep(0.1) @@ -383,45 +744,116 @@ def test_embeddings_no_pii(sentry_init, capture_events, clear_litellm_cache): (event,) = events assert event["type"] == "transaction" - assert len(event["spans"]) == 1 - (span,) = event["spans"] + 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"] -def test_exception_handling(sentry_init, capture_events): +@pytest.mark.asyncio(loop_scope="session") +async def test_async_embeddings_no_pii( + sentry_init, + capture_events, + get_model_response, + openai_embedding_model_response, + clear_litellm_cache, +): + """Test that PII is not captured when disabled.""" sentry_init( - integrations=[LiteLLMIntegration()], + integrations=[LiteLLMIntegration(include_prompts=True)], traces_sample_rate=1.0, + send_default_pii=False, # PII disabled ) events = capture_events() - messages = [{"role": "user", "content": "Hello!"}] - - with start_transaction(name="litellm test"): - kwargs = { - "model": "gpt-3.5-turbo", - "messages": messages, - } + client = AsyncOpenAI(api_key="test-key") - _input_callback(kwargs) - _failure_callback( - kwargs, - Exception("API rate limit reached"), - datetime.now(), - datetime.now(), - ) + model_response = get_model_response( + openai_embedding_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) - # Should have error event and transaction + 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"] + + +def test_exception_handling( + reset_litellm_executor, sentry_init, capture_events, get_rate_limit_model_response +): + sentry_init( + integrations=[LiteLLMIntegration()], + traces_sample_rate=1.0, + ) + events = capture_events() + + messages = [{"role": "user", "content": "Hello!"}] + + client = OpenAI(api_key="test-key") + + model_response = get_rate_limit_model_response() + + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with start_transaction(name="litellm test"): + with 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"] assert len(error_events) == 1 -def test_span_origin(sentry_init, capture_events): +@pytest.mark.asyncio(loop_scope="session") +async def test_async_exception_handling( + sentry_init, capture_events, get_rate_limit_model_response +): sentry_init( integrations=[LiteLLMIntegration()], traces_sample_rate=1.0, @@ -429,21 +861,67 @@ def test_span_origin(sentry_init, capture_events): events = capture_events() messages = [{"role": "user", "content": "Hello!"}] - mock_response = MockCompletionResponse() - with start_transaction(name="litellm test"): - kwargs = { - "model": "gpt-3.5-turbo", - "messages": messages, - } + client = AsyncOpenAI(api_key="test-key") - _input_callback(kwargs) - _success_callback( - kwargs, - mock_response, - datetime.now(), - datetime.now(), - ) + model_response = get_rate_limit_model_response() + + with mock.patch.object( + client.embeddings._client._client, + "send", + return_value=model_response, + ): + with start_transaction(name="litellm test"): + with 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"] + assert len(error_events) == 1 + + +def test_span_origin( + reset_litellm_executor, + sentry_init, + capture_events, + get_model_response, + nonstreaming_chat_completions_model_response, +): + sentry_init( + integrations=[LiteLLMIntegration()], + traces_sample_rate=1.0, + ) + events = capture_events() + + messages = [{"role": "user", "content": "Hello!"}] + + client = OpenAI(api_key="test-key") + + model_response = get_model_response( + nonstreaming_chat_completions_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with start_transaction(name="litellm test"): + litellm.completion( + model="gpt-3.5-turbo", + messages=messages, + client=client, + ) + + litellm_utils.executor.shutdown(wait=True) (event,) = events @@ -451,7 +929,15 @@ def test_span_origin(sentry_init, capture_events): assert event["spans"][0]["origin"] == "auto.ai.litellm" -def test_multiple_providers(sentry_init, capture_events): +def test_multiple_providers( + reset_litellm_executor, + sentry_init, + capture_events, + get_model_response, + nonstreaming_chat_completions_model_response, + nonstreaming_anthropic_model_response, + nonstreaming_google_genai_model_response, +): """Test that the integration correctly identifies different providers.""" sentry_init( integrations=[LiteLLMIntegration()], @@ -461,38 +947,186 @@ def test_multiple_providers(sentry_init, capture_events): messages = [{"role": "user", "content": "Hello!"}] - # Test with different model prefixes - test_cases = [ - ("gpt-3.5-turbo", "openai"), - ("claude-3-opus-20240229", "anthropic"), - ("gemini/gemini-pro", "gemini"), - ] + openai_client = OpenAI(api_key="test-key") + openai_model_response = get_model_response( + nonstreaming_chat_completions_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, + ): + with 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"}, + ) + + with mock.patch.object( + anthropic_client, + "post", + return_value=anthropic_model_response, + ): + with 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, + ): + with 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 + + 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.asyncio(loop_scope="session") +async def test_async_multiple_providers( + sentry_init, + capture_events, + get_model_response, + nonstreaming_chat_completions_model_response, + nonstreaming_anthropic_model_response, + nonstreaming_google_genai_model_response, +): + """Test that the integration correctly identifies different providers.""" + sentry_init( + integrations=[LiteLLMIntegration()], + traces_sample_rate=1.0, + ) + events = capture_events() + + messages = [{"role": "user", "content": "Hello!"}] - for model, _ in test_cases: - mock_response = MockCompletionResponse(model=model) - with start_transaction(name=f"test {model}"): - kwargs = { - "model": model, - "messages": messages, - } - - _input_callback(kwargs) - _success_callback( - kwargs, - mock_response, - datetime.now(), - datetime.now(), + openai_client = AsyncOpenAI(api_key="test-key") + openai_model_response = get_model_response( + nonstreaming_chat_completions_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, + ): + with start_transaction(name="test gpt-3.5-turbo"): + await litellm.acompletion( + model="gpt-3.5-turbo", + messages=messages, + client=openai_client, ) - assert len(events) == len(test_cases) + await GLOBAL_LOGGING_WORKER.flush() + await asyncio.sleep(0.5) + + _reset_litellm_executor() - for i in range(len(test_cases)): + 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, + ): + with 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, + ): + with 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) + + 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"] -def test_additional_parameters(sentry_init, capture_events): +def test_additional_parameters( + reset_litellm_executor, + sentry_init, + capture_events, + get_model_response, + nonstreaming_chat_completions_model_response, +): """Test that additional parameters are captured.""" sentry_init( integrations=[LiteLLMIntegration()], @@ -501,29 +1135,41 @@ def test_additional_parameters(sentry_init, capture_events): events = capture_events() messages = [{"role": "user", "content": "Hello!"}] - mock_response = MockCompletionResponse() + client = OpenAI(api_key="test-key") - with start_transaction(name="litellm test"): - kwargs = { - "model": "gpt-3.5-turbo", - "messages": messages, - "temperature": 0.7, - "max_tokens": 100, - "top_p": 0.9, - "frequency_penalty": 0.5, - "presence_penalty": 0.5, - } + model_response = get_model_response( + nonstreaming_chat_completions_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) - _input_callback(kwargs) - _success_callback( - kwargs, - mock_response, - datetime.now(), - datetime.now(), - ) + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with 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 - (span,) = event["spans"] + 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["data"][SPANDATA.GEN_AI_REQUEST_TEMPERATURE] == 0.7 assert span["data"][SPANDATA.GEN_AI_REQUEST_MAX_TOKENS] == 100 @@ -532,8 +1178,14 @@ def test_additional_parameters(sentry_init, capture_events): assert span["data"][SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY] == 0.5 -def test_litellm_specific_parameters(sentry_init, capture_events): - """Test that LiteLLM-specific parameters are captured.""" +@pytest.mark.asyncio(loop_scope="session") +async def test_async_additional_parameters( + sentry_init, + capture_events, + get_model_response, + nonstreaming_chat_completions_model_response, +): + """Test that additional parameters are captured.""" sentry_init( integrations=[LiteLLMIntegration()], traces_sample_rate=1.0, @@ -541,34 +1193,57 @@ def test_litellm_specific_parameters(sentry_init, capture_events): events = capture_events() messages = [{"role": "user", "content": "Hello!"}] - mock_response = MockCompletionResponse() + client = AsyncOpenAI(api_key="test-key") - with start_transaction(name="litellm test"): - kwargs = { - "model": "gpt-3.5-turbo", - "messages": messages, - "api_base": "https://custom-api.example.com", - "api_version": "2023-01-01", - "custom_llm_provider": "custom_provider", - } + model_response = get_model_response( + nonstreaming_chat_completions_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) - _input_callback(kwargs) - _success_callback( - kwargs, - mock_response, - datetime.now(), - datetime.now(), - ) + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with 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 - (span,) = event["spans"] + 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["data"]["gen_ai.litellm.api_base"] == "https://custom-api.example.com" - assert span["data"]["gen_ai.litellm.api_version"] == "2023-01-01" - assert span["data"]["gen_ai.litellm.custom_llm_provider"] == "custom_provider" + 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 -def test_no_integration(sentry_init, capture_events): +def test_no_integration( + reset_litellm_executor, + sentry_init, + capture_events, + get_model_response, + nonstreaming_chat_completions_model_response, +): """Test that when integration is not enabled, callbacks don't break.""" sentry_init( traces_sample_rate=1.0, @@ -576,28 +1251,85 @@ def test_no_integration(sentry_init, capture_events): events = capture_events() messages = [{"role": "user", "content": "Hello!"}] - mock_response = MockCompletionResponse() + client = OpenAI(api_key="test-key") - with start_transaction(name="litellm test"): - # When the integration isn't enabled, the callbacks should exit early - kwargs = { - "model": "gpt-3.5-turbo", - "messages": messages, - } + model_response = get_model_response( + nonstreaming_chat_completions_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) - # These should not crash, just do nothing - _input_callback(kwargs) - _success_callback( - kwargs, - mock_response, - datetime.now(), - datetime.now(), - ) + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with 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" + ) + assert len(chat_spans) == 0 + + +@pytest.mark.asyncio(loop_scope="session") +async def test_async_no_integration( + sentry_init, + capture_events, + get_model_response, + nonstreaming_chat_completions_model_response, +): + """Test that when integration is not enabled, callbacks don't break.""" + sentry_init( + traces_sample_rate=1.0, + ) + events = capture_events() + + messages = [{"role": "user", "content": "Hello!"}] + client = AsyncOpenAI(api_key="test-key") + + model_response = get_model_response( + nonstreaming_chat_completions_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with 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" - assert len(event.get("spans", [])) == 0 + 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) == 0 def test_response_without_usage(sentry_init, capture_events): @@ -655,50 +1387,6 @@ def test_integration_setup(sentry_init): assert _failure_callback in (litellm.failure_callback or []) -def test_message_dict_extraction(sentry_init, capture_events): - """Test that response messages are properly extracted with dict() fallback.""" - sentry_init( - integrations=[LiteLLMIntegration(include_prompts=True)], - traces_sample_rate=1.0, - send_default_pii=True, - ) - events = capture_events() - - messages = [{"role": "user", "content": "Hello!"}] - - # Create a message that has dict() method instead of model_dump() - class DictMessage: - def __init__(self): - self.role = "assistant" - self.content = "Response" - self.tool_calls = None - - def dict(self): - return {"role": self.role, "content": self.content} - - mock_response = MockCompletionResponse(choices=[MockChoice(message=DictMessage())]) - - 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"] - - # Should have extracted the response message - assert SPANDATA.GEN_AI_RESPONSE_TEXT in span["data"] - - def test_litellm_message_truncation(sentry_init, capture_events): """Test that large messages are truncated properly in LiteLLM integration.""" sentry_init( @@ -761,7 +1449,13 @@ def test_litellm_message_truncation(sentry_init, capture_events): IMAGE_DATA_URI = f"data:image/png;base64,{IMAGE_B64}" -def test_binary_content_encoding_image_url(sentry_init, capture_events): +def test_binary_content_encoding_image_url( + reset_litellm_executor, + sentry_init, + capture_events, + get_model_response, + nonstreaming_chat_completions_model_response, +): sentry_init( integrations=[LiteLLMIntegration(include_prompts=True)], traces_sample_rate=1.0, @@ -781,15 +1475,116 @@ def test_binary_content_encoding_image_url(sentry_init, capture_events): ], } ] - mock_response = MockCompletionResponse() + client = OpenAI(api_key="test-key") - with start_transaction(name="litellm test"): - kwargs = {"model": "gpt-4-vision-preview", "messages": messages} - _input_callback(kwargs) - _success_callback(kwargs, mock_response, datetime.now(), datetime.now()) + model_response = get_model_response( + nonstreaming_chat_completions_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with 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 - (span,) = event["spans"] + 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]) + + blob_item = next( + ( + item + for msg in messages_data + if "content" in msg + for item in msg["content"] + if item.get("type") == "blob" + ), + None, + ) + assert blob_item is not None + assert blob_item["modality"] == "image" + assert blob_item["mime_type"] == "image/png" + assert ( + IMAGE_B64 in blob_item["content"] + or blob_item["content"] == BLOB_DATA_SUBSTITUTE + ) + + +@pytest.mark.asyncio(loop_scope="session") +async def test_async_binary_content_encoding_image_url( + sentry_init, + capture_events, + get_model_response, + nonstreaming_chat_completions_model_response, +): + sentry_init( + integrations=[LiteLLMIntegration(include_prompts=True)], + traces_sample_rate=1.0, + send_default_pii=True, + ) + events = capture_events() + + messages = [ + { + "role": "user", + "content": [ + {"type": "text", "text": "Look at this image:"}, + { + "type": "image_url", + "image_url": {"url": IMAGE_DATA_URI, "detail": "high"}, + }, + ], + } + ] + client = AsyncOpenAI(api_key="test-key") + + model_response = get_model_response( + nonstreaming_chat_completions_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with 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]) blob_item = next( @@ -811,7 +1606,13 @@ def test_binary_content_encoding_image_url(sentry_init, capture_events): ) -def test_binary_content_encoding_mixed_content(sentry_init, capture_events): +def test_binary_content_encoding_mixed_content( + reset_litellm_executor, + sentry_init, + capture_events, + get_model_response, + nonstreaming_chat_completions_model_response, +): sentry_init( integrations=[LiteLLMIntegration(include_prompts=True)], traces_sample_rate=1.0, @@ -832,15 +1633,37 @@ def test_binary_content_encoding_mixed_content(sentry_init, capture_events): ], } ] - mock_response = MockCompletionResponse() + client = OpenAI(api_key="test-key") - with start_transaction(name="litellm test"): - kwargs = {"model": "gpt-4-vision-preview", "messages": messages} - _input_callback(kwargs) - _success_callback(kwargs, mock_response, datetime.now(), datetime.now()) + model_response = get_model_response( + nonstreaming_chat_completions_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with 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 - (span,) = event["spans"] + 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]) content_items = [ @@ -850,7 +1673,81 @@ def test_binary_content_encoding_mixed_content(sentry_init, capture_events): assert any(item.get("type") == "blob" for item in content_items) -def test_binary_content_encoding_uri_type(sentry_init, capture_events): +@pytest.mark.asyncio(loop_scope="session") +async def test_async_binary_content_encoding_mixed_content( + sentry_init, + capture_events, + get_model_response, + nonstreaming_chat_completions_model_response, +): + sentry_init( + integrations=[LiteLLMIntegration(include_prompts=True)], + traces_sample_rate=1.0, + send_default_pii=True, + ) + events = capture_events() + + messages = [ + { + "role": "user", + "content": [ + {"type": "text", "text": "Here is an image:"}, + { + "type": "image_url", + "image_url": {"url": IMAGE_DATA_URI}, + }, + {"type": "text", "text": "What do you see?"}, + ], + } + ] + client = AsyncOpenAI(api_key="test-key") + + model_response = get_model_response( + nonstreaming_chat_completions_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with 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]) + + content_items = [ + item for msg in messages_data if "content" in msg for item in msg["content"] + ] + assert any(item.get("type") == "text" for item in content_items) + assert any(item.get("type") == "blob" for item in content_items) + + +def test_binary_content_encoding_uri_type( + reset_litellm_executor, + sentry_init, + capture_events, + get_model_response, + nonstreaming_chat_completions_model_response, +): sentry_init( integrations=[LiteLLMIntegration(include_prompts=True)], traces_sample_rate=1.0, @@ -869,15 +1766,110 @@ def test_binary_content_encoding_uri_type(sentry_init, capture_events): ], } ] - mock_response = MockCompletionResponse() + client = OpenAI(api_key="test-key") - with start_transaction(name="litellm test"): - kwargs = {"model": "gpt-4-vision-preview", "messages": messages} - _input_callback(kwargs) - _success_callback(kwargs, mock_response, datetime.now(), datetime.now()) + model_response = get_model_response( + nonstreaming_chat_completions_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with 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 - (span,) = event["spans"] + 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]) + + uri_item = next( + ( + item + for msg in messages_data + if "content" in msg + for item in msg["content"] + if item.get("type") == "uri" + ), + None, + ) + assert uri_item is not None + assert uri_item["uri"] == "https://example.com/image.jpg" + + +@pytest.mark.asyncio(loop_scope="session") +async def test_async_binary_content_encoding_uri_type( + sentry_init, + capture_events, + get_model_response, + nonstreaming_chat_completions_model_response, +): + sentry_init( + integrations=[LiteLLMIntegration(include_prompts=True)], + traces_sample_rate=1.0, + send_default_pii=True, + ) + events = capture_events() + + messages = [ + { + "role": "user", + "content": [ + { + "type": "image_url", + "image_url": {"url": "https://example.com/image.jpg"}, + } + ], + } + ] + client = AsyncOpenAI(api_key="test-key") + + model_response = get_model_response( + nonstreaming_chat_completions_model_response, + serialize_pydantic=True, + request_headers={"X-Stainless-Raw-Response": "true"}, + ) + + with mock.patch.object( + client.completions._client._client, + "send", + return_value=model_response, + ): + with 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]) uri_item = next( diff --git a/tests/integrations/openai/test_openai.py b/tests/integrations/openai/test_openai.py index 23fb0d9ad7..ada2e633de 100644 --- a/tests/integrations/openai/test_openai.py +++ b/tests/integrations/openai/test_openai.py @@ -41,10 +41,11 @@ SKIP_RESPONSES_TESTS = True from sentry_sdk import start_transaction -from sentry_sdk.consts import SPANDATA +from sentry_sdk.consts import SPANDATA, OP from sentry_sdk.integrations.openai import ( OpenAIIntegration, - _calculate_token_usage, + _calculate_completions_token_usage, + _calculate_responses_token_usage, ) from sentry_sdk.utils import safe_serialize @@ -151,6 +152,11 @@ def test_nonstreaming_chat_completion_no_prompts( {"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 @@ -161,6 +167,15 @@ def test_nonstreaming_chat_completion_no_prompts( 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"] @@ -230,6 +245,11 @@ def test_nonstreaming_chat_completion(sentry_init, capture_events, messages, req client.chat.completions.create( model="some-model", messages=messages, + max_tokens=100, + presence_penalty=0.1, + frequency_penalty=0.2, + temperature=0.7, + top_p=0.9, ) .choices[0] .message.content @@ -240,6 +260,15 @@ def test_nonstreaming_chat_completion(sentry_init, capture_events, messages, req 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 param_id = request.node.callspec.id if "blocks" in param_id: @@ -298,6 +327,11 @@ async def test_nonstreaming_chat_completion_async_no_prompts( {"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 @@ -306,6 +340,15 @@ async def test_nonstreaming_chat_completion_async_no_prompts( 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"] @@ -377,6 +420,11 @@ async def test_nonstreaming_chat_completion_async( response = await client.chat.completions.create( model="some-model", messages=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 @@ -385,6 +433,15 @@ async def test_nonstreaming_chat_completion_async( 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 param_id = request.node.callspec.id if "blocks" in param_id: @@ -433,7 +490,12 @@ def tiktoken_encoding_if_installed(): ], ) def test_streaming_chat_completion_no_prompts( - sentry_init, capture_events, send_default_pii, include_prompts + sentry_init, + capture_events, + send_default_pii, + include_prompts, + get_model_response, + server_side_event_chunks, ): sentry_init( integrations=[ @@ -448,61 +510,90 @@ def test_streaming_chat_completion_no_prompts( events = capture_events() client = OpenAI(api_key="z") - returned_stream = Stream(cast_to=None, response=None, client=client) - returned_stream._iterator = [ - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=0, delta=ChoiceDelta(content="hel"), finish_reason=None - ) - ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=1, delta=ChoiceDelta(content="lo "), finish_reason=None - ) - ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=2, delta=ChoiceDelta(content="world"), finish_reason="stop" - ) - ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ] - - 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": "You are a helpful assistant."}, - {"role": "user", "content": "hello"}, + returned_stream = get_model_response( + server_side_event_chunks( + [ + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=0, + delta=ChoiceDelta(content="hel"), + finish_reason=None, + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=1, + delta=ChoiceDelta(content="lo "), + finish_reason=None, + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=2, + delta=ChoiceDelta(content="world"), + finish_reason="stop", + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), ], - stream=True, - ) - response_string = "".join( - map(lambda x: x.choices[0].delta.content, response_stream) + include_event_type=False, ) + ) + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + with 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 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" @@ -520,6 +611,304 @@ def test_streaming_chat_completion_no_prompts( pass # if tiktoken is not installed, we can't guarantee token usage will be calculated properly +@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, + get_model_response, + server_side_event_chunks, +): + """When stream_options=include_usage is set, token usage comes from the final chunk's usage field.""" + sentry_init( + integrations=[OpenAIIntegration(include_prompts=False)], + traces_sample_rate=1.0, + send_default_pii=False, + ) + events = capture_events() + + client = OpenAI(api_key="z") + returned_stream = get_model_response( + server_side_event_chunks( + [ + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=0, + delta=ChoiceDelta(content="hel"), + finish_reason=None, + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=0, + delta=ChoiceDelta(content="lo"), + finish_reason="stop", + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + usage=CompletionUsage( + prompt_tokens=20, + completion_tokens=10, + total_tokens=30, + ), + ), + ], + include_event_type=False, + ) + ) + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + with 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 + + +@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, + get_model_response, + server_side_event_chunks, +): + """Token usage from the stream is recorded even when no content is produced (e.g. content filter).""" + sentry_init( + integrations=[OpenAIIntegration(include_prompts=False)], + traces_sample_rate=1.0, + send_default_pii=False, + ) + events = capture_events() + + client = OpenAI(api_key="z") + returned_stream = get_model_response( + server_side_event_chunks( + [ + ChatCompletionChunk( + id="1", + choices=[], + created=100000, + model="model-id", + object="chat.completion.chunk", + usage=CompletionUsage( + prompt_tokens=20, + completion_tokens=0, + total_tokens=20, + ), + ), + ], + include_event_type=False, + ) + ) + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + with 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 + + +@pytest.mark.skipif( + OPENAI_VERSION <= (1, 1, 0), + reason="OpenAI versions <=1.1.0 do not support the stream_options parameter.", +) +@pytest.mark.asyncio +async def test_streaming_chat_completion_empty_content_preserves_token_usage_async( + sentry_init, + capture_events, + get_model_response, + async_iterator, + server_side_event_chunks, +): + """Token usage from the stream is recorded even when no content is produced - async variant.""" + sentry_init( + integrations=[OpenAIIntegration(include_prompts=False)], + traces_sample_rate=1.0, + send_default_pii=False, + ) + events = capture_events() + + client = AsyncOpenAI(api_key="z") + returned_stream = get_model_response( + async_iterator( + server_side_event_chunks( + [ + ChatCompletionChunk( + id="1", + choices=[], + created=100000, + model="model-id", + object="chat.completion.chunk", + usage=CompletionUsage( + prompt_tokens=20, + completion_tokens=0, + total_tokens=20, + ), + ), + ], + include_event_type=False, + ) + ) + ) + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + with 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 + + +@pytest.mark.skipif( + OPENAI_VERSION <= (1, 1, 0), + reason="OpenAI versions <=1.1.0 do not support the stream_options parameter.", +) +@pytest.mark.asyncio +async def test_streaming_chat_completion_async_with_usage_in_stream( + sentry_init, + capture_events, + get_model_response, + async_iterator, + server_side_event_chunks, +): + """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)], + traces_sample_rate=1.0, + send_default_pii=False, + ) + events = capture_events() + + client = AsyncOpenAI(api_key="z") + returned_stream = get_model_response( + async_iterator( + server_side_event_chunks( + [ + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=0, + delta=ChoiceDelta(content="hel"), + finish_reason=None, + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=0, + delta=ChoiceDelta(content="lo"), + finish_reason="stop", + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + usage=CompletionUsage( + prompt_tokens=20, + completion_tokens=10, + total_tokens=30, + ), + ), + ], + include_event_type=False, + ) + ) + ) + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + with 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 + + # noinspection PyTypeChecker @pytest.mark.parametrize( "messages", @@ -564,7 +953,14 @@ def test_streaming_chat_completion_no_prompts( ), ], ) -def test_streaming_chat_completion(sentry_init, capture_events, messages, request): +def test_streaming_chat_completion( + sentry_init, + capture_events, + messages, + request, + get_model_response, + server_side_event_chunks, +): sentry_init( integrations=[ OpenAIIntegration( @@ -578,58 +974,86 @@ def test_streaming_chat_completion(sentry_init, capture_events, messages, reques events = capture_events() client = OpenAI(api_key="z") - returned_stream = Stream(cast_to=None, response=None, client=client) - returned_stream._iterator = [ - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=0, delta=ChoiceDelta(content="hel"), finish_reason=None - ) - ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=1, delta=ChoiceDelta(content="lo "), finish_reason=None - ) - ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=2, delta=ChoiceDelta(content="world"), finish_reason="stop" - ) + returned_stream = get_model_response( + server_side_event_chunks( + [ + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=0, + delta=ChoiceDelta(content="hel"), + finish_reason=None, + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=1, + delta=ChoiceDelta(content="lo "), + finish_reason=None, + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=2, + delta=ChoiceDelta(content="world"), + finish_reason="stop", + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ] - - 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=messages, - stream=True, - ) - response_string = "".join( - map(lambda x: x.choices[0].delta.content, response_stream) + include_event_type=False, ) + ) + + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + with start_transaction(name="openai tx"): + response_stream = client.chat.completions.create( + model="some-model", + messages=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 param_id = request.node.callspec.id if "blocks" in param_id: @@ -682,7 +1106,13 @@ def test_streaming_chat_completion(sentry_init, capture_events, messages, reques ], ) async def test_streaming_chat_completion_async_no_prompts( - sentry_init, capture_events, send_default_pii, include_prompts, async_iterator + sentry_init, + capture_events, + send_default_pii, + include_prompts, + get_model_response, + async_iterator, + server_side_event_chunks, ): sentry_init( integrations=[ @@ -697,67 +1127,93 @@ async def test_streaming_chat_completion_async_no_prompts( events = capture_events() client = AsyncOpenAI(api_key="z") - returned_stream = AsyncStream(cast_to=None, response=None, client=client) - returned_stream._iterator = async_iterator( - [ - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=0, delta=ChoiceDelta(content="hel"), finish_reason=None - ) - ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=1, delta=ChoiceDelta(content="lo "), finish_reason=None - ) - ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=2, - delta=ChoiceDelta(content="world"), - finish_reason="stop", - ) + returned_stream = get_model_response( + async_iterator( + server_side_event_chunks( + [ + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=0, + delta=ChoiceDelta(content="hel"), + finish_reason=None, + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=1, + delta=ChoiceDelta(content="lo "), + finish_reason=None, + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=2, + delta=ChoiceDelta(content="world"), + finish_reason="stop", + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ] + include_event_type=False, + ) + ) ) - client.chat.completions._post = AsyncMock(return_value=returned_stream) - with 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, - ) + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + with 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 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" @@ -822,7 +1278,13 @@ async def test_streaming_chat_completion_async_no_prompts( ], ) async def test_streaming_chat_completion_async( - sentry_init, capture_events, messages, request, async_iterator + sentry_init, + capture_events, + messages, + request, + get_model_response, + async_iterator, + server_side_event_chunks, ): sentry_init( integrations=[ @@ -837,64 +1299,91 @@ async def test_streaming_chat_completion_async( events = capture_events() client = AsyncOpenAI(api_key="z") - returned_stream = AsyncStream(cast_to=None, response=None, client=client) - returned_stream._iterator = async_iterator( - [ - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=0, delta=ChoiceDelta(content="hel"), finish_reason=None - ) - ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=1, delta=ChoiceDelta(content="lo "), finish_reason=None - ) - ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=2, - delta=ChoiceDelta(content="world"), - finish_reason="stop", - ) - ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ] + + returned_stream = get_model_response( + async_iterator( + server_side_event_chunks( + [ + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=0, + delta=ChoiceDelta(content="hel"), + finish_reason=None, + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=1, + delta=ChoiceDelta(content="lo "), + finish_reason=None, + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=2, + delta=ChoiceDelta(content="world"), + finish_reason="stop", + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), + ], + include_event_type=False, + ) + ) ) - client.chat.completions._post = AsyncMock(return_value=returned_stream) - with start_transaction(name="openai tx"): - response_stream = await client.chat.completions.create( - model="some-model", - messages=messages, - stream=True, - ) + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + with start_transaction(name="openai tx"): + response_stream = await client.chat.completions.create( + model="some-model", + messages=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 + 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" @@ -1036,6 +1525,8 @@ def test_embeddings_create_no_pii( 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 SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["data"] @@ -1116,6 +1607,8 @@ def test_embeddings_create(sentry_init, capture_events, input, request): 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" param_id = request.node.callspec.id if param_id == "string": @@ -1187,6 +1680,8 @@ async def test_embeddings_create_async_no_pii( 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 SPANDATA.GEN_AI_EMBEDDINGS_INPUT not in span["data"] @@ -1270,6 +1765,8 @@ async def test_embeddings_create_async(sentry_init, capture_events, input, reque 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" param_id = request.node.callspec.id if param_id == "string": @@ -1582,7 +2079,8 @@ async def test_span_origin_embeddings_async(sentry_init, capture_events): assert event["spans"][0]["origin"] == "auto.ai.openai" -def test_calculate_token_usage_a(): +def test_completions_token_usage_from_response(): + """Token counts are extracted from response.usage using Completions API field names.""" span = mock.MagicMock() def count_tokens(msg): @@ -1599,8 +2097,13 @@ def count_tokens(msg): with mock.patch( "sentry_sdk.integrations.openai.record_token_usage" ) as mock_record_token_usage: - _calculate_token_usage( - messages, response, span, streaming_message_responses, count_tokens + _calculate_completions_token_usage( + messages=messages, + response=response, + span=span, + streaming_message_responses=streaming_message_responses, + streaming_message_total_token_usage=None, + count_tokens=count_tokens, ) mock_record_token_usage.assert_called_once_with( span, @@ -1612,7 +2115,46 @@ def count_tokens(msg): ) -def test_calculate_token_usage_b(): +def test_completions_token_usage_with_detailed_fields(): + """Cached and reasoning token counts are extracted from prompt_tokens_details and completion_tokens_details.""" + span = mock.MagicMock() + + def count_tokens(msg): + return len(str(msg)) + + response = mock.MagicMock() + response.usage = mock.MagicMock() + response.usage.prompt_tokens = 20 + response.usage.prompt_tokens_details = mock.MagicMock() + response.usage.prompt_tokens_details.cached_tokens = 5 + response.usage.completion_tokens = 10 + response.usage.completion_tokens_details = mock.MagicMock() + response.usage.completion_tokens_details.reasoning_tokens = 8 + response.usage.total_tokens = 30 + + with mock.patch( + "sentry_sdk.integrations.openai.record_token_usage" + ) as mock_record_token_usage: + _calculate_completions_token_usage( + messages=[], + response=response, + span=span, + streaming_message_responses=[], + streaming_message_total_token_usage=None, + count_tokens=count_tokens, + ) + mock_record_token_usage.assert_called_once_with( + span, + input_tokens=20, + input_tokens_cached=5, + output_tokens=10, + output_tokens_reasoning=8, + total_tokens=30, + ) + + +def test_completions_token_usage_manual_input_counting(): + """When prompt_tokens is missing, input tokens are counted manually from messages.""" span = mock.MagicMock() def count_tokens(msg): @@ -1632,8 +2174,13 @@ def count_tokens(msg): with mock.patch( "sentry_sdk.integrations.openai.record_token_usage" ) as mock_record_token_usage: - _calculate_token_usage( - messages, response, span, streaming_message_responses, count_tokens + _calculate_completions_token_usage( + messages=messages, + response=response, + span=span, + streaming_message_responses=streaming_message_responses, + streaming_message_total_token_usage=None, + count_tokens=count_tokens, ) mock_record_token_usage.assert_called_once_with( span, @@ -1645,7 +2192,8 @@ def count_tokens(msg): ) -def test_calculate_token_usage_c(): +def test_completions_token_usage_manual_output_counting_streaming(): + """When completion_tokens is missing, output tokens are counted from streaming responses.""" span = mock.MagicMock() def count_tokens(msg): @@ -1665,8 +2213,13 @@ def count_tokens(msg): with mock.patch( "sentry_sdk.integrations.openai.record_token_usage" ) as mock_record_token_usage: - _calculate_token_usage( - messages, response, span, streaming_message_responses, count_tokens + _calculate_completions_token_usage( + messages=messages, + response=response, + span=span, + streaming_message_responses=streaming_message_responses, + streaming_message_total_token_usage=None, + count_tokens=count_tokens, ) mock_record_token_usage.assert_called_once_with( span, @@ -1678,7 +2231,8 @@ def count_tokens(msg): ) -def test_calculate_token_usage_d(): +def test_completions_token_usage_manual_output_counting_choices(): + """When completion_tokens is missing, output tokens are counted from response.choices.""" span = mock.MagicMock() def count_tokens(msg): @@ -1689,30 +2243,48 @@ def count_tokens(msg): response.usage.prompt_tokens = 20 response.usage.total_tokens = 20 response.choices = [ - mock.MagicMock(message="one"), - mock.MagicMock(message="two"), - mock.MagicMock(message="three"), + Choice( + index=0, + finish_reason="stop", + message=ChatCompletionMessage(role="assistant", content="one"), + ), + Choice( + index=1, + finish_reason="stop", + message=ChatCompletionMessage(role="assistant", content="two"), + ), + Choice( + index=2, + finish_reason="stop", + message=ChatCompletionMessage(role="assistant", content="three"), + ), ] messages = [] - streaming_message_responses = [] + streaming_message_responses = None with mock.patch( "sentry_sdk.integrations.openai.record_token_usage" ) as mock_record_token_usage: - _calculate_token_usage( - messages, response, span, streaming_message_responses, count_tokens + _calculate_completions_token_usage( + messages=messages, + response=response, + span=span, + streaming_message_responses=streaming_message_responses, + streaming_message_total_token_usage=None, + count_tokens=count_tokens, ) mock_record_token_usage.assert_called_once_with( span, input_tokens=20, input_tokens_cached=None, - output_tokens=None, + output_tokens=11, output_tokens_reasoning=None, total_tokens=20, ) -def test_calculate_token_usage_e(): +def test_completions_token_usage_no_usage_data(): + """When response has no usage data and no streaming responses, all tokens are None.""" span = mock.MagicMock() def count_tokens(msg): @@ -1725,8 +2297,75 @@ def count_tokens(msg): with mock.patch( "sentry_sdk.integrations.openai.record_token_usage" ) as mock_record_token_usage: - _calculate_token_usage( - messages, response, span, streaming_message_responses, count_tokens + _calculate_completions_token_usage( + messages=messages, + response=response, + span=span, + streaming_message_responses=streaming_message_responses, + streaming_message_total_token_usage=None, + count_tokens=count_tokens, + ) + mock_record_token_usage.assert_called_once_with( + span, + input_tokens=None, + input_tokens_cached=None, + output_tokens=None, + output_tokens_reasoning=None, + total_tokens=None, + ) + + +@pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") +def test_responses_token_usage_from_response(): + """Token counts including cached and reasoning tokens are extracted from Responses API.""" + span = mock.MagicMock() + + def count_tokens(msg): + return len(str(msg)) + + response = mock.MagicMock() + response.usage = mock.MagicMock() + response.usage.input_tokens = 20 + response.usage.input_tokens_details = mock.MagicMock() + response.usage.input_tokens_details.cached_tokens = 5 + response.usage.output_tokens = 10 + response.usage.output_tokens_details = mock.MagicMock() + response.usage.output_tokens_details.reasoning_tokens = 8 + response.usage.total_tokens = 30 + input = [] + + with mock.patch( + "sentry_sdk.integrations.openai.record_token_usage" + ) as mock_record_token_usage: + _calculate_responses_token_usage(input, response, span, None, count_tokens) + mock_record_token_usage.assert_called_once_with( + span, + input_tokens=20, + input_tokens_cached=5, + output_tokens=10, + output_tokens_reasoning=8, + total_tokens=30, + ) + + +@pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") +def test_responses_token_usage_no_usage_data(): + """When Responses API response has no usage data, all tokens are None.""" + span = mock.MagicMock() + + def count_tokens(msg): + return len(str(msg)) + + response = mock.MagicMock() + response.usage = None + input = [] + streaming_message_responses = None + + with mock.patch( + "sentry_sdk.integrations.openai.record_token_usage" + ) as mock_record_token_usage: + _calculate_responses_token_usage( + input, response, span, streaming_message_responses, count_tokens ) mock_record_token_usage.assert_called_once_with( span, @@ -1738,6 +2377,70 @@ def count_tokens(msg): ) +@pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") +def test_responses_token_usage_manual_output_counting_response_output(): + """When output_tokens is missing, output tokens are counted from response.output.""" + span = mock.MagicMock() + + def count_tokens(msg): + return len(str(msg)) + + response = mock.MagicMock() + response.usage = mock.MagicMock() + response.usage.input_tokens = 20 + response.usage.total_tokens = 20 + response.output = [ + ResponseOutputMessage( + id="msg-1", + content=[ + ResponseOutputText( + annotations=[], + text="one", + type="output_text", + ), + ], + role="assistant", + status="completed", + type="message", + ), + ResponseOutputMessage( + id="msg-2", + content=[ + ResponseOutputText( + annotations=[], + text="two", + type="output_text", + ), + ResponseOutputText( + annotations=[], + text="three", + type="output_text", + ), + ], + role="assistant", + status="completed", + type="message", + ), + ] + input = [] + streaming_message_responses = None + + with mock.patch( + "sentry_sdk.integrations.openai.record_token_usage" + ) as mock_record_token_usage: + _calculate_responses_token_usage( + input, response, span, streaming_message_responses, count_tokens + ) + mock_record_token_usage.assert_called_once_with( + span, + input_tokens=20, + input_tokens_cached=None, + output_tokens=11, + output_tokens_reasoning=None, + total_tokens=20, + ) + + @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_ai_client_span_responses_api_no_pii(sentry_init, capture_events): sentry_init( @@ -1754,6 +2457,9 @@ def test_ai_client_span_responses_api_no_pii(sentry_init, capture_events): 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, ) (transaction,) = events @@ -1764,8 +2470,12 @@ def test_ai_client_span_responses_api_no_pii(sentry_init, capture_events): assert spans[0]["origin"] == "auto.ai.openai" assert spans[0]["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.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, @@ -1864,6 +2574,9 @@ def test_ai_client_span_responses_api( model="gpt-4o", instructions=instructions, input=input, + max_output_tokens=100, + temperature=0.7, + top_p=0.9, ) (transaction,) = events @@ -1875,8 +2588,12 @@ def test_ai_client_span_responses_api( 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.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, @@ -2166,6 +2883,9 @@ async def test_ai_client_span_responses_async_api( model="gpt-4o", instructions=instructions, input=input, + max_output_tokens=100, + temperature=0.7, + top_p=0.9, ) (transaction,) = events @@ -2177,9 +2897,13 @@ async def test_ai_client_span_responses_async_api( 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.messages": '["How do I check if a Python object is an instance of a class?"]', "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, @@ -2415,7 +3139,14 @@ 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, instructions, input, request, async_iterator + sentry_init, + capture_events, + instructions, + input, + request, + get_model_response, + async_iterator, + server_side_event_chunks, ): sentry_init( integrations=[OpenAIIntegration(include_prompts=True)], @@ -2425,29 +3156,39 @@ async def test_ai_client_span_streaming_responses_async_api( events = capture_events() client = AsyncOpenAI(api_key="z") - returned_stream = AsyncStream(cast_to=None, response=None, client=client) - returned_stream._iterator = async_iterator(EXAMPLE_RESPONSES_STREAM) - client.responses._post = mock.AsyncMock(return_value=returned_stream) + returned_stream = get_model_response( + async_iterator(server_side_event_chunks(EXAMPLE_RESPONSES_STREAM)) + ) - with start_transaction(name="openai tx"): - result = await client.responses.create( - model="gpt-4o", - instructions=instructions, - input=input, - stream=True, - ) - async for _ in result: - pass + with mock.patch.object( + client.responses._client._client, + "send", + return_value=returned_stream, + ): + with 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, + ) + async for _ in result: + pass (transaction,) = events - spans = transaction["spans"] + spans = [span for span in transaction["spans"] if span["op"] == OP.GEN_AI_RESPONSES] 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.response.model": "response-model-id", "gen_ai.response.streaming": True, "gen_ai.system": "openai", @@ -2737,7 +3478,12 @@ async def test_error_in_responses_async_api(sentry_init, capture_events): ) @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") def test_streaming_responses_api( - sentry_init, capture_events, send_default_pii, include_prompts + sentry_init, + capture_events, + send_default_pii, + include_prompts, + get_model_response, + server_side_event_chunks, ): sentry_init( integrations=[ @@ -2751,27 +3497,41 @@ def test_streaming_responses_api( events = capture_events() client = OpenAI(api_key="z") - returned_stream = Stream(cast_to=None, response=None, client=client) - returned_stream._iterator = EXAMPLE_RESPONSES_STREAM - client.responses._post = mock.Mock(return_value=returned_stream) - - with start_transaction(name="openai tx"): - response_stream = client.responses.create( - model="some-model", - input="hello", - stream=True, + returned_stream = get_model_response( + server_side_event_chunks( + EXAMPLE_RESPONSES_STREAM, ) + ) + + with mock.patch.object( + client.responses._client._client, + "send", + return_value=returned_stream, + ): + with 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, + ) - 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" (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_RESPONSE_MODEL] == "response-model-id" @@ -2794,7 +3554,13 @@ def test_streaming_responses_api( ) @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") async def test_streaming_responses_api_async( - sentry_init, capture_events, send_default_pii, include_prompts, async_iterator + sentry_init, + capture_events, + send_default_pii, + include_prompts, + get_model_response, + async_iterator, + server_side_event_chunks, ): sentry_init( integrations=[ @@ -2808,27 +3574,39 @@ async def test_streaming_responses_api_async( events = capture_events() client = AsyncOpenAI(api_key="z") - returned_stream = AsyncStream(cast_to=None, response=None, client=client) - returned_stream._iterator = async_iterator(EXAMPLE_RESPONSES_STREAM) - client.responses._post = AsyncMock(return_value=returned_stream) + returned_stream = get_model_response( + async_iterator(server_side_event_chunks(EXAMPLE_RESPONSES_STREAM)) + ) - with start_transaction(name="openai tx"): - response_stream = await client.responses.create( - model="some-model", - input="hello", - stream=True, - ) + with mock.patch.object( + client.responses._client._client, + "send", + return_value=returned_stream, + ): + with 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, + ) - 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" (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_RESPONSE_MODEL] == "response-model-id" @@ -2970,7 +3748,9 @@ def test_openai_message_truncation(sentry_init, capture_events): # noinspection PyTypeChecker -def test_streaming_chat_completion_ttft(sentry_init, capture_events): +def test_streaming_chat_completion_ttft( + sentry_init, capture_events, get_model_response, server_side_event_chunks +): """ Test that streaming chat completions capture time-to-first-token (TTFT). """ @@ -2981,43 +3761,54 @@ def test_streaming_chat_completion_ttft(sentry_init, capture_events): events = capture_events() client = OpenAI(api_key="z") - returned_stream = Stream(cast_to=None, response=None, client=client) - returned_stream._iterator = [ - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=0, delta=ChoiceDelta(content="Hello"), finish_reason=None - ) - ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=0, delta=ChoiceDelta(content=" world"), finish_reason="stop" - ) + returned_stream = get_model_response( + server_side_event_chunks( + [ + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=0, + delta=ChoiceDelta(content="Hello"), + finish_reason=None, + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=0, + delta=ChoiceDelta(content=" world"), + finish_reason="stop", + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), ], - created=100000, - model="model-id", - object="chat.completion.chunk", + include_event_type=False, ), - ] - - 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": "user", "content": "Say hello"}], - stream=True, - ) - # Consume the stream - for _ in response_stream: - pass + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + with 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] @@ -3033,7 +3824,11 @@ def test_streaming_chat_completion_ttft(sentry_init, capture_events): # noinspection PyTypeChecker @pytest.mark.asyncio async def test_streaming_chat_completion_ttft_async( - sentry_init, capture_events, async_iterator + sentry_init, + capture_events, + get_model_response, + async_iterator, + server_side_event_chunks, ): """ Test that async streaming chat completions capture time-to-first-token (TTFT). @@ -3045,47 +3840,56 @@ async def test_streaming_chat_completion_ttft_async( events = capture_events() client = AsyncOpenAI(api_key="z") - returned_stream = AsyncStream(cast_to=None, response=None, client=client) - returned_stream._iterator = async_iterator( - [ - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=0, delta=ChoiceDelta(content="Hello"), finish_reason=None - ) - ], - created=100000, - model="model-id", - object="chat.completion.chunk", - ), - ChatCompletionChunk( - id="1", - choices=[ - DeltaChoice( - index=0, - delta=ChoiceDelta(content=" world"), - finish_reason="stop", - ) + returned_stream = get_model_response( + async_iterator( + server_side_event_chunks( + [ + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=0, + delta=ChoiceDelta(content="Hello"), + finish_reason=None, + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), + ChatCompletionChunk( + id="1", + choices=[ + DeltaChoice( + index=0, + delta=ChoiceDelta(content=" world"), + finish_reason="stop", + ) + ], + created=100000, + model="model-id", + object="chat.completion.chunk", + ), ], - created=100000, - model="model-id", - object="chat.completion.chunk", + include_event_type=False, ), - ] + ) ) - client.chat.completions._post = AsyncMock(return_value=returned_stream) - - with 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 + with mock.patch.object( + client.chat._client._client, + "send", + return_value=returned_stream, + ): + with 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] @@ -3100,7 +3904,9 @@ async def test_streaming_chat_completion_ttft_async( # noinspection PyTypeChecker @pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available") -def test_streaming_responses_api_ttft(sentry_init, capture_events): +def test_streaming_responses_api_ttft( + sentry_init, capture_events, get_model_response, server_side_event_chunks +): """ Test that streaming responses API captures time-to-first-token (TTFT). """ @@ -3111,19 +3917,24 @@ def test_streaming_responses_api_ttft(sentry_init, capture_events): events = capture_events() client = OpenAI(api_key="z") - returned_stream = Stream(cast_to=None, response=None, client=client) - returned_stream._iterator = EXAMPLE_RESPONSES_STREAM - client.responses._post = mock.Mock(return_value=returned_stream) + returned_stream = get_model_response( + server_side_event_chunks(EXAMPLE_RESPONSES_STREAM) + ) - with 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 + with mock.patch.object( + client.responses._client._client, + "send", + return_value=returned_stream, + ): + with 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] @@ -3140,7 +3951,11 @@ def test_streaming_responses_api_ttft(sentry_init, capture_events): @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, async_iterator + sentry_init, + capture_events, + get_model_response, + async_iterator, + server_side_event_chunks, ): """ Test that async streaming responses API captures time-to-first-token (TTFT). @@ -3152,19 +3967,24 @@ async def test_streaming_responses_api_ttft_async( events = capture_events() client = AsyncOpenAI(api_key="z") - returned_stream = AsyncStream(cast_to=None, response=None, client=client) - returned_stream._iterator = async_iterator(EXAMPLE_RESPONSES_STREAM) - client.responses._post = AsyncMock(return_value=returned_stream) + returned_stream = get_model_response( + async_iterator(server_side_event_chunks(EXAMPLE_RESPONSES_STREAM)) + ) - with 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 + with mock.patch.object( + client.responses._client._client, + "send", + return_value=returned_stream, + ): + with 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] diff --git a/tests/integrations/openai_agents/test_openai_agents.py b/tests/integrations/openai_agents/test_openai_agents.py index 9edaa8501a..7310e86df5 100644 --- a/tests/integrations/openai_agents/test_openai_agents.py +++ b/tests/integrations/openai_agents/test_openai_agents.py @@ -102,45 +102,6 @@ def mock_usage(): ) -@pytest.fixture -def mock_model_response(): - return Response( - id="resp_123", - output=[ - ResponseOutputMessage( - id="msg_123", - type="message", - status="completed", - content=[ - ResponseOutputText( - text="Hello, how can I help you?", - 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, - ), - output_tokens=20, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=5, - ), - total_tokens=30, - ), - ) - - @pytest.fixture def test_agent(): """Create a real Agent instance for testing.""" @@ -198,13 +159,19 @@ def test_agent_custom_model(): @pytest.mark.asyncio async def test_agent_invocation_span_no_pii( - sentry_init, capture_events, test_agent, mock_model_response, get_model_response + sentry_init, + capture_events, + test_agent, + nonstreaming_responses_model_response, + get_model_response, ): client = AsyncOpenAI(api_key="test-key") model = OpenAIResponsesModel(model="gpt-4", openai_client=client) agent = test_agent.clone(model=model) - response = get_model_response(mock_model_response, serialize_pydantic=True) + response = get_model_response( + nonstreaming_responses_model_response, serialize_pydantic=True + ) with patch.object( agent.model._client._client, @@ -340,7 +307,7 @@ async def test_agent_invocation_span( sentry_init, capture_events, test_agent_with_instructions, - mock_model_response, + nonstreaming_responses_model_response, instructions, input, request, @@ -353,7 +320,9 @@ async def test_agent_invocation_span( model = OpenAIResponsesModel(model="gpt-4", openai_client=client) agent = test_agent_with_instructions(instructions).clone(model=model) - response = get_model_response(mock_model_response, serialize_pydantic=True) + response = get_model_response( + nonstreaming_responses_model_response, serialize_pydantic=True + ) with patch.object( agent.model._client._client, @@ -503,7 +472,7 @@ async def test_client_span_custom_model( sentry_init, capture_events, test_agent_custom_model, - mock_model_response, + nonstreaming_responses_model_response, get_model_response, ): """ @@ -514,7 +483,9 @@ async def test_client_span_custom_model( model = OpenAIResponsesModel(model="my-custom-model", openai_client=client) agent = test_agent_custom_model.clone(model=model) - response = get_model_response(mock_model_response, serialize_pydantic=True) + response = get_model_response( + nonstreaming_responses_model_response, serialize_pydantic=True + ) with patch.object( agent.model._client._client, @@ -547,7 +518,7 @@ def test_agent_invocation_span_sync_no_pii( sentry_init, capture_events, test_agent, - mock_model_response, + nonstreaming_responses_model_response, get_model_response, ): """ @@ -557,7 +528,9 @@ def test_agent_invocation_span_sync_no_pii( model = OpenAIResponsesModel(model="gpt-4", openai_client=client) agent = test_agent.clone(model=model) - response = get_model_response(mock_model_response, serialize_pydantic=True) + response = get_model_response( + nonstreaming_responses_model_response, serialize_pydantic=True + ) with patch.object( agent.model._client._client, @@ -687,7 +660,7 @@ def test_agent_invocation_span_sync( sentry_init, capture_events, test_agent_with_instructions, - mock_model_response, + nonstreaming_responses_model_response, instructions, input, request, @@ -700,7 +673,9 @@ def test_agent_invocation_span_sync( model = OpenAIResponsesModel(model="gpt-4", openai_client=client) agent = test_agent_with_instructions(instructions).clone(model=model) - response = get_model_response(mock_model_response, serialize_pydantic=True) + response = get_model_response( + nonstreaming_responses_model_response, serialize_pydantic=True + ) with patch.object( agent.model._client._client, @@ -1087,7 +1062,11 @@ async def test_max_turns_before_handoff_span( @pytest.mark.asyncio async def test_tool_execution_span( - sentry_init, capture_events, test_agent, get_model_response + sentry_init, + capture_events, + test_agent, + get_model_response, + responses_tool_call_model_responses, ): """ Test tool execution span creation. @@ -1103,75 +1082,45 @@ def simple_test_tool(message: str) -> str: model = OpenAIResponsesModel(model="gpt-4", openai_client=client) agent_with_tool = test_agent.clone(tools=[simple_test_tool], model=model) - tool_response = get_model_response( - Response( - id="resp_tool_123", - output=[ - ResponseFunctionToolCall( - id="call_123", - call_id="call_123", - name="simple_test_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, + responses = 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, + ), + output_tokens=5, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=0, + ), + total_tokens=15, ), - output_tokens=5, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=0, + ResponseUsage( + input_tokens=15, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + ), + output_tokens=10, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=0, + ), + total_tokens=25, ), - total_tokens=15, - ), + ] ), + ) + 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="Task completed using the tool", - 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=15, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - ), - output_tokens=10, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=0, - ), - total_tokens=25, - ), - ), + next(responses), serialize_pydantic=True, ) @@ -1325,8 +1274,6 @@ def simple_test_tool(message: str) -> str: 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 tool_span["data"]["gen_ai.tool.type"] == "function" - 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" @@ -1370,7 +1317,11 @@ def simple_test_tool(message: str) -> str: @pytest.mark.asyncio async def test_hosted_mcp_tool_propagation_header_streamed( - sentry_init, test_agent, async_iterator, server_side_event_chunks + sentry_init, + test_agent, + get_model_response, + async_iterator, + server_side_event_chunks, ): """ Test responses API is given trace propagation headers with HostedMCPTool. @@ -1402,11 +1353,7 @@ async def test_hosted_mcp_tool_propagation_header_streamed( release="d08ebdb9309e1b004c6f52202de58a09c2268e42", ) - request = httpx.Request( - "POST", - "/responses", - ) - + 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: @@ -1414,12 +1361,10 @@ async def test_hosted_mcp_tool_propagation_header_streamed( 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" + request_headers["X-Stainless-Raw-Response"] = "stream" - response = httpx.Response( - 200, - request=request, - content=async_iterator( + response = get_model_response( + async_iterator( server_side_event_chunks( [ ResponseCreatedEvent( @@ -1478,6 +1423,7 @@ async def test_hosted_mcp_tool_propagation_header_streamed( ] ) ), + request_headers=request_headers, ) # Patching https://github.com/openai/openai-python/blob/656e3cab4a18262a49b961d41293367e45ee71b9/src/openai/_base_client.py#L1604 @@ -1948,17 +1894,13 @@ async def test_mcp_tool_execution_spans( # Find the MCP execute_tool span mcp_tool_span = None for span in spans: - if ( - span.get("description") == "execute_tool test_mcp_tool" - and span.get("data", {}).get("gen_ai.tool.type") == "mcp" - ): + if span.get("description") == "execute_tool test_mcp_tool": mcp_tool_span = span break # Verify the MCP tool span was created assert mcp_tool_span is not None, "MCP execute_tool span was not created" assert mcp_tool_span["description"] == "execute_tool test_mcp_tool" - assert mcp_tool_span["data"]["gen_ai.tool.type"] == "mcp" assert mcp_tool_span["data"]["gen_ai.tool.name"] == "test_mcp_tool" assert mcp_tool_span["data"]["gen_ai.tool.input"] == '{"query": "search term"}' assert ( @@ -2080,17 +2022,13 @@ async def test_mcp_tool_execution_with_error( # Find the MCP execute_tool span with error mcp_tool_span = None for span in spans: - if ( - span.get("description") == "execute_tool failing_mcp_tool" - and span.get("data", {}).get("gen_ai.tool.type") == "mcp" - ): + if span.get("description") == "execute_tool failing_mcp_tool": mcp_tool_span = span break # Verify the MCP tool span was created with error status assert mcp_tool_span is not None, "MCP execute_tool span was not created" assert mcp_tool_span["description"] == "execute_tool failing_mcp_tool" - assert mcp_tool_span["data"]["gen_ai.tool.type"] == "mcp" assert mcp_tool_span["data"]["gen_ai.tool.name"] == "failing_mcp_tool" assert mcp_tool_span["data"]["gen_ai.tool.input"] == '{"query": "test"}' assert mcp_tool_span["data"]["gen_ai.tool.output"] is None @@ -2210,17 +2148,13 @@ async def test_mcp_tool_execution_without_pii( # Find the MCP execute_tool span mcp_tool_span = None for span in spans: - if ( - span.get("description") == "execute_tool test_mcp_tool" - and span.get("data", {}).get("gen_ai.tool.type") == "mcp" - ): + if span.get("description") == "execute_tool test_mcp_tool": mcp_tool_span = span break # Verify the MCP tool span was created but without input/output assert mcp_tool_span is not None, "MCP execute_tool span was not created" assert mcp_tool_span["description"] == "execute_tool test_mcp_tool" - assert mcp_tool_span["data"]["gen_ai.tool.type"] == "mcp" assert mcp_tool_span["data"]["gen_ai.tool.name"] == "test_mcp_tool" # Verify input and output are not included when send_default_pii is False @@ -2230,7 +2164,11 @@ async def test_mcp_tool_execution_without_pii( @pytest.mark.asyncio async def test_multiple_agents_asyncio( - sentry_init, capture_events, test_agent, mock_model_response, get_model_response + sentry_init, + capture_events, + test_agent, + nonstreaming_responses_model_response, + get_model_response, ): """ Test that multiple agents can be run at the same time in asyncio tasks @@ -2240,7 +2178,9 @@ async def test_multiple_agents_asyncio( model = OpenAIResponsesModel(model="gpt-4", openai_client=client) agent = test_agent.clone(model=model) - response = get_model_response(mock_model_response, serialize_pydantic=True) + response = get_model_response( + nonstreaming_responses_model_response, serialize_pydantic=True + ) with patch.object( agent.model._client._client, @@ -2318,7 +2258,11 @@ def test_openai_agents_message_role_mapping( @pytest.mark.asyncio async def test_tool_execution_error_tracing( - sentry_init, capture_events, test_agent, get_model_response + sentry_init, + capture_events, + test_agent, + get_model_response, + responses_tool_call_model_responses, ): """ Test that tool execution errors are properly tracked via error tracing patch. @@ -2341,75 +2285,45 @@ def failing_tool(message: str) -> str: model = OpenAIResponsesModel(model="gpt-4", openai_client=client) agent_with_tool = test_agent.clone(tools=[failing_tool], model=model) - tool_response = get_model_response( - Response( - id="resp_1", - output=[ - ResponseFunctionToolCall( - id="call_123", - call_id="call_123", - name="failing_tool", - type="function_call", - arguments='{"message": "test"}', - ) - ], - 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, + responses = 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, + ), + output_tokens=5, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=0, + ), + total_tokens=15, ), - output_tokens=5, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=0, + ResponseUsage( + input_tokens=15, + input_tokens_details=InputTokensDetails( + cached_tokens=0, + ), + output_tokens=10, + output_tokens_details=OutputTokensDetails( + reasoning_tokens=0, + ), + total_tokens=25, ), - total_tokens=15, - ), + ] ), + ) + tool_response = get_model_response( + next(responses), serialize_pydantic=True, ) - final_response = get_model_response( - Response( - id="resp_2", - output=[ - ResponseOutputMessage( - id="msg_final", - type="message", - status="completed", - content=[ - ResponseOutputText( - text="An error occurred while running the tool", - 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=15, - input_tokens_details=InputTokensDetails( - cached_tokens=0, - ), - output_tokens=10, - output_tokens_details=OutputTokensDetails( - reasoning_tokens=0, - ), - total_tokens=25, - ), - ), + next(responses), serialize_pydantic=True, ) @@ -2440,7 +2354,10 @@ def failing_tool(message: str) -> str: # Find the execute_tool span execute_tool_span = None for span in spans: - if span.get("description", "").startswith("execute_tool failing_tool"): + description = span.get("description", "") + if description is not None and description.startswith( + "execute_tool failing_tool" + ): execute_tool_span = span break @@ -3154,7 +3071,11 @@ async def test_streaming_span_update_captures_response_data( @pytest.mark.asyncio async def test_streaming_ttft_on_chat_span( - sentry_init, test_agent, async_iterator, server_side_event_chunks + sentry_init, + test_agent, + get_model_response, + async_iterator, + server_side_event_chunks, ): """ Test that time-to-first-token (TTFT) is recorded on chat spans during streaming. @@ -3182,11 +3103,7 @@ async def test_streaming_ttft_on_chat_span( traces_sample_rate=1.0, ) - request = httpx.Request( - "POST", - "/responses", - ) - + 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: @@ -3194,12 +3111,10 @@ async def test_streaming_ttft_on_chat_span( 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" + request_headers["X-Stainless-Raw-Response"] = "stream" - response = httpx.Response( - 200, - request=request, - content=async_iterator( + response = get_model_response( + async_iterator( server_side_event_chunks( [ ResponseCreatedEvent( @@ -3276,6 +3191,7 @@ async def test_streaming_ttft_on_chat_span( ] ) ), + request_headers=request_headers, ) # Patching https://github.com/openai/openai-python/blob/656e3cab4a18262a49b961d41293367e45ee71b9/src/openai/_base_client.py#L1604 @@ -3313,7 +3229,11 @@ async def test_streaming_ttft_on_chat_span( ) @pytest.mark.asyncio async def test_conversation_id_on_all_spans( - sentry_init, capture_events, test_agent, mock_model_response, get_model_response + sentry_init, + capture_events, + 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(). @@ -3323,7 +3243,9 @@ async def test_conversation_id_on_all_spans( model = OpenAIResponsesModel(model="gpt-4", openai_client=client) agent = test_agent.clone(model=model) - response = get_model_response(mock_model_response, serialize_pydantic=True) + response = get_model_response( + nonstreaming_responses_model_response, serialize_pydantic=True + ) with patch.object( agent.model._client._client, @@ -3508,7 +3430,7 @@ async def test_no_conversation_id_when_not_provided( sentry_init, capture_events, test_agent, - mock_model_response, + nonstreaming_responses_model_response, get_model_response, ): """ @@ -3519,7 +3441,9 @@ async def test_no_conversation_id_when_not_provided( model = OpenAIResponsesModel(model="gpt-4", openai_client=client) agent = test_agent.clone(model=model) - response = get_model_response(mock_model_response, serialize_pydantic=True) + response = get_model_response( + nonstreaming_responses_model_response, serialize_pydantic=True + ) with patch.object( agent.model._client._client, diff --git a/tests/integrations/opentelemetry/test_span_processor.py b/tests/integrations/opentelemetry/test_span_processor.py index af5cbdd3fb..e1cd849b94 100644 --- a/tests/integrations/opentelemetry/test_span_processor.py +++ b/tests/integrations/opentelemetry/test_span_processor.py @@ -68,7 +68,9 @@ def test_get_trace_data_with_span_and_trace(): parent_context = {} span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context) + 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 @@ -90,7 +92,9 @@ def test_get_trace_data_with_span_and_trace_and_parent(): parent_context = {} span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context) + 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" @@ -121,7 +125,9 @@ def test_get_trace_data_with_sentry_trace(): ], ): span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context) + 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" @@ -138,7 +144,9 @@ def test_get_trace_data_with_sentry_trace(): ], ): span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context) + 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" @@ -175,7 +183,9 @@ def test_get_trace_data_with_sentry_trace_and_baggage(): ], ): span_processor = SentrySpanProcessor() - sentry_trace_data = span_processor._get_trace_data(otel_span, parent_context) + 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" diff --git a/tests/integrations/pydantic_ai/test_pydantic_ai.py b/tests/integrations/pydantic_ai/test_pydantic_ai.py index f0ddc6c4ed..50ce155f5b 100644 --- a/tests/integrations/pydantic_ai/test_pydantic_ai.py +++ b/tests/integrations/pydantic_ai/test_pydantic_ai.py @@ -16,37 +16,44 @@ from pydantic_ai.messages import BinaryContent, ImageUrl, UserPromptPart from pydantic_ai.usage import RequestUsage from pydantic_ai.exceptions import ModelRetry, UnexpectedModelBehavior +from pydantic_ai.models.function import FunctionModel @pytest.fixture -def test_agent(): - """Create a test agent with model settings.""" - return Agent( - "test", - name="test_agent", - system_prompt="You are a helpful test assistant.", - ) +def get_test_agent(): + def inner(): + """Create a test agent with model settings.""" + return Agent( + "test", + name="test_agent", + system_prompt="You are a helpful test assistant.", + ) + + return inner @pytest.fixture -def test_agent_with_settings(): - """Create a test agent with explicit model settings.""" - from pydantic_ai import ModelSettings +def get_test_agent_with_settings(): + def inner(): + """Create a test agent with explicit model settings.""" + from pydantic_ai import ModelSettings + + return Agent( + "test", + name="test_agent_settings", + system_prompt="You are a test assistant with settings.", + model_settings=ModelSettings( + temperature=0.7, + max_tokens=100, + top_p=0.9, + ), + ) - return Agent( - "test", - name="test_agent_settings", - system_prompt="You are a test assistant with settings.", - model_settings=ModelSettings( - temperature=0.7, - max_tokens=100, - top_p=0.9, - ), - ) + return inner @pytest.mark.asyncio -async def test_agent_run_async(sentry_init, capture_events, test_agent): +async def test_agent_run_async(sentry_init, capture_events, get_test_agent): """ Test that the integration creates spans for async agent runs. """ @@ -58,6 +65,7 @@ async def test_agent_run_async(sentry_init, capture_events, test_agent): events = capture_events() + test_agent = get_test_agent() result = await test_agent.run("Test input") assert result is not None @@ -88,7 +96,36 @@ async def test_agent_run_async(sentry_init, capture_events, test_agent): @pytest.mark.asyncio -async def test_agent_run_async_usage_data(sentry_init, capture_events, test_agent): +async def test_agent_run_async_model_error(sentry_init, capture_events): + sentry_init( + integrations=[PydanticAIIntegration()], + traces_sample_rate=1.0, + ) + + events = capture_events() + + def failing_model(messages, info): + raise RuntimeError("model exploded") + + agent = Agent( + FunctionModel(failing_model), + name="test_agent", + ) + + with pytest.raises(RuntimeError, match="model exploded"): + await agent.run("Test input") + + (error, transaction) = events + assert error["level"] == "error" + + spans = transaction["spans"] + assert len(spans) == 1 + + assert spans[0]["status"] == "internal_error" + + +@pytest.mark.asyncio +async def test_agent_run_async_usage_data(sentry_init, capture_events, get_test_agent): """ Test that the invoke_agent span includes token usage and model data. """ @@ -100,6 +137,7 @@ async def test_agent_run_async_usage_data(sentry_init, capture_events, test_agen events = capture_events() + test_agent = get_test_agent() result = await test_agent.run("Test input") assert result is not None @@ -132,7 +170,7 @@ async def test_agent_run_async_usage_data(sentry_init, capture_events, test_agen assert trace_data["gen_ai.response.model"] == "test" # Test model name -def test_agent_run_sync(sentry_init, capture_events, test_agent): +def test_agent_run_sync(sentry_init, capture_events, get_test_agent): """ Test that the integration creates spans for sync agent runs. """ @@ -144,6 +182,7 @@ def test_agent_run_sync(sentry_init, capture_events, test_agent): events = capture_events() + test_agent = get_test_agent() result = test_agent.run_sync("Test input") assert result is not None @@ -165,8 +204,36 @@ def test_agent_run_sync(sentry_init, capture_events, test_agent): assert chat_span["data"]["gen_ai.response.streaming"] is False +def test_agent_run_sync_model_error(sentry_init, capture_events): + sentry_init( + integrations=[PydanticAIIntegration()], + traces_sample_rate=1.0, + ) + + events = capture_events() + + def failing_model(messages, info): + raise RuntimeError("model exploded") + + agent = Agent( + FunctionModel(failing_model), + name="test_agent", + ) + + with pytest.raises(RuntimeError, match="model exploded"): + agent.run_sync("Test input") + + (error, transaction) = events + assert error["level"] == "error" + + spans = transaction["spans"] + assert len(spans) == 1 + + assert spans[0]["status"] == "internal_error" + + @pytest.mark.asyncio -async def test_agent_run_stream(sentry_init, capture_events, test_agent): +async def test_agent_run_stream(sentry_init, capture_events, get_test_agent): """ Test that the integration creates spans for streaming agent runs. """ @@ -178,6 +245,7 @@ async def test_agent_run_stream(sentry_init, capture_events, test_agent): events = capture_events() + test_agent = get_test_agent() async with test_agent.run_stream("Test input") as result: # Consume the stream async for _ in result.stream_output(): @@ -207,7 +275,7 @@ async def test_agent_run_stream(sentry_init, capture_events, test_agent): @pytest.mark.asyncio -async def test_agent_run_stream_events(sentry_init, capture_events, test_agent): +async def test_agent_run_stream_events(sentry_init, capture_events, get_test_agent): """ Test that run_stream_events creates spans (it uses run internally, so non-streaming). """ @@ -220,6 +288,7 @@ async def test_agent_run_stream_events(sentry_init, capture_events, test_agent): events = capture_events() # Consume all events + test_agent = get_test_agent() async for _ in test_agent.run_stream_events("Test input"): pass @@ -239,22 +308,23 @@ async def test_agent_run_stream_events(sentry_init, capture_events, test_agent): @pytest.mark.asyncio -async def test_agent_with_tools(sentry_init, capture_events, test_agent): +async def test_agent_with_tools(sentry_init, capture_events, get_test_agent): """ Test that tool execution creates execute_tool spans. """ - - @test_agent.tool_plain - def add_numbers(a: int, b: int) -> int: - """Add two numbers together.""" - return a + b - sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, ) + test_agent = get_test_agent() + + @test_agent.tool_plain + def add_numbers(a: int, b: int) -> int: + """Add two numbers together.""" + return a + b + events = capture_events() result = await test_agent.run("What is 5 + 3?") @@ -275,7 +345,6 @@ def add_numbers(a: int, b: int) -> int: 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.type"] == "function" 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"] @@ -294,14 +363,25 @@ def add_numbers(a: int, b: int) -> int: ) @pytest.mark.asyncio async def test_agent_with_tool_model_retry( - sentry_init, capture_events, test_agent, handled_tool_call_exceptions + sentry_init, capture_events, get_test_agent, handled_tool_call_exceptions ): """ Test that a handled exception is captured when a tool raises ModelRetry. """ + sentry_init( + integrations=[ + PydanticAIIntegration( + handled_tool_call_exceptions=handled_tool_call_exceptions + ) + ], + traces_sample_rate=1.0, + send_default_pii=True, + ) retries = 0 + test_agent = get_test_agent() + @test_agent.tool_plain def add_numbers(a: int, b: int) -> float: """Add two numbers together, but raises an exception on the first attempt.""" @@ -311,16 +391,6 @@ def add_numbers(a: int, b: int) -> float: raise ModelRetry(message="Try again with the same arguments.") return a + b - sentry_init( - integrations=[ - PydanticAIIntegration( - handled_tool_call_exceptions=handled_tool_call_exceptions - ) - ], - traces_sample_rate=1.0, - send_default_pii=True, - ) - events = capture_events() result = await test_agent.run("What is 5 + 3?") @@ -348,14 +418,12 @@ def add_numbers(a: int, b: int) -> float: 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.type"] == "function" 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.type"] == "function" 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"] @@ -374,17 +442,11 @@ def add_numbers(a: int, b: int) -> float: ) @pytest.mark.asyncio async def test_agent_with_tool_validation_error( - sentry_init, capture_events, test_agent, handled_tool_call_exceptions + sentry_init, capture_events, get_test_agent, handled_tool_call_exceptions ): """ Test that a handled exception is captured when a tool has unsatisfiable constraints. """ - - @test_agent.tool_plain - def add_numbers(a: Annotated[int, Field(gt=0, lt=0)], b: int) -> int: - """Add two numbers together.""" - return a + b - sentry_init( integrations=[ PydanticAIIntegration( @@ -395,6 +457,13 @@ def add_numbers(a: Annotated[int, Field(gt=0, lt=0)], b: int) -> int: send_default_pii=True, ) + test_agent = get_test_agent() + + @test_agent.tool_plain + def add_numbers(a: Annotated[int, Field(gt=0, lt=0)], b: int) -> int: + """Add two numbers together.""" + return a + b + events = capture_events() result = None @@ -427,7 +496,6 @@ def add_numbers(a: Annotated[int, Field(gt=0, lt=0)], b: int) -> int: 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.type"] == "function" assert model_retry_tool_span["data"]["gen_ai.tool.name"] == "add_numbers" assert "gen_ai.tool.input" in model_retry_tool_span["data"] @@ -440,22 +508,23 @@ def add_numbers(a: Annotated[int, Field(gt=0, lt=0)], b: int) -> int: @pytest.mark.asyncio -async def test_agent_with_tools_streaming(sentry_init, capture_events, test_agent): +async def test_agent_with_tools_streaming(sentry_init, capture_events, get_test_agent): """ Test that tool execution works correctly with streaming. """ - - @test_agent.tool_plain - def multiply(a: int, b: int) -> int: - """Multiply two numbers.""" - return a * b - sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, ) + test_agent = get_test_agent() + + @test_agent.tool_plain + def multiply(a: int, b: int) -> int: + """Multiply two numbers.""" + return a * b + events = capture_events() async with test_agent.run_stream("What is 7 times 8?") as result: @@ -484,7 +553,9 @@ def multiply(a: int, b: int) -> int: @pytest.mark.asyncio -async def test_model_settings(sentry_init, capture_events, test_agent_with_settings): +async def test_model_settings( + sentry_init, capture_events, get_test_agent_with_settings +): """ Test that model settings are captured in spans. """ @@ -495,6 +566,7 @@ async def test_model_settings(sentry_init, capture_events, test_agent_with_setti events = capture_events() + test_agent_with_settings = get_test_agent_with_settings() await test_agent_with_settings.run("Test input") (transaction,) = events @@ -596,7 +668,7 @@ async def test_error_handling(sentry_init, capture_events): @pytest.mark.asyncio -async def test_without_pii(sentry_init, capture_events, test_agent): +async def test_without_pii(sentry_init, capture_events, get_test_agent): """ Test that PII is not captured when send_default_pii is False. """ @@ -608,6 +680,7 @@ async def test_without_pii(sentry_init, capture_events, test_agent): events = capture_events() + test_agent = get_test_agent() await test_agent.run("Sensitive input") (transaction,) = events @@ -623,22 +696,23 @@ async def test_without_pii(sentry_init, capture_events, test_agent): @pytest.mark.asyncio -async def test_without_pii_tools(sentry_init, capture_events, test_agent): +async def test_without_pii_tools(sentry_init, capture_events, get_test_agent): """ Test that tool input/output are not captured when send_default_pii is False. """ - - @test_agent.tool_plain - def sensitive_tool(data: str) -> str: - """A tool with sensitive data.""" - return f"Processed: {data}" - sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=False, ) + test_agent = get_test_agent() + + @test_agent.tool_plain + def sensitive_tool(data: str) -> str: + """A tool with sensitive data.""" + return f"Processed: {data}" + events = capture_events() await test_agent.run("Use sensitive tool with private data") @@ -656,7 +730,7 @@ def sensitive_tool(data: str) -> str: @pytest.mark.asyncio -async def test_multiple_agents_concurrent(sentry_init, capture_events, test_agent): +async def test_multiple_agents_concurrent(sentry_init, capture_events, get_test_agent): """ Test that multiple agents can run concurrently without interfering. """ @@ -667,6 +741,8 @@ async def test_multiple_agents_concurrent(sentry_init, capture_events, test_agen events = capture_events() + test_agent = get_test_agent() + async def run_agent(input_text): return await test_agent.run(input_text) @@ -737,7 +813,7 @@ async def test_message_history(sentry_init, capture_events): @pytest.mark.asyncio -async def test_gen_ai_system(sentry_init, capture_events, test_agent): +async def test_gen_ai_system(sentry_init, capture_events, get_test_agent): """ Test that gen_ai.system is set from the model. """ @@ -748,6 +824,7 @@ async def test_gen_ai_system(sentry_init, capture_events, test_agent): events = capture_events() + test_agent = get_test_agent() await test_agent.run("Test input") (transaction,) = events @@ -764,7 +841,7 @@ async def test_gen_ai_system(sentry_init, capture_events, test_agent): @pytest.mark.asyncio -async def test_include_prompts_false(sentry_init, capture_events, test_agent): +async def test_include_prompts_false(sentry_init, capture_events, get_test_agent): """ Test that prompts are not captured when include_prompts=False. """ @@ -776,6 +853,7 @@ async def test_include_prompts_false(sentry_init, capture_events, test_agent): events = capture_events() + test_agent = get_test_agent() await test_agent.run("Sensitive prompt") (transaction,) = events @@ -791,7 +869,7 @@ async def test_include_prompts_false(sentry_init, capture_events, test_agent): @pytest.mark.asyncio -async def test_include_prompts_true(sentry_init, capture_events, test_agent): +async def test_include_prompts_true(sentry_init, capture_events, get_test_agent): """ Test that prompts are captured when include_prompts=True (default). """ @@ -803,6 +881,7 @@ async def test_include_prompts_true(sentry_init, capture_events, test_agent): events = capture_events() + test_agent = get_test_agent() await test_agent.run("Test prompt") (transaction,) = events @@ -819,23 +898,24 @@ async def test_include_prompts_true(sentry_init, capture_events, test_agent): @pytest.mark.asyncio async def test_include_prompts_false_with_tools( - sentry_init, capture_events, test_agent + sentry_init, capture_events, get_test_agent ): """ Test that tool input/output are not captured when include_prompts=False. """ - - @test_agent.tool_plain - def test_tool(value: int) -> int: - """A test tool.""" - return value * 2 - sentry_init( integrations=[PydanticAIIntegration(include_prompts=False)], traces_sample_rate=1.0, send_default_pii=True, ) + test_agent = get_test_agent() + + @test_agent.tool_plain + def test_tool(value: int) -> int: + """A test tool.""" + return value * 2 + events = capture_events() await test_agent.run("Use the test tool with value 5") @@ -853,7 +933,9 @@ def test_tool(value: int) -> int: @pytest.mark.asyncio -async def test_include_prompts_requires_pii(sentry_init, capture_events, test_agent): +async def test_include_prompts_requires_pii( + sentry_init, capture_events, get_test_agent +): """ Test that include_prompts requires send_default_pii=True. """ @@ -865,6 +947,7 @@ async def test_include_prompts_requires_pii(sentry_init, capture_events, test_ag events = capture_events() + test_agent = get_test_agent() await test_agent.run("Test prompt") (transaction,) = events @@ -1015,7 +1098,7 @@ async def mock_map_tool_result_part(part): @pytest.mark.asyncio -async def test_context_cleanup_after_run(sentry_init, test_agent): +async def test_context_cleanup_after_run(sentry_init, get_test_agent): """ Test that the pydantic_ai_agent context is properly cleaned up after agent execution. """ @@ -1031,13 +1114,14 @@ async def test_context_cleanup_after_run(sentry_init, test_agent): assert "pydantic_ai_agent" not in scope._contexts # Run the agent + test_agent = get_test_agent() await test_agent.run("Test input") # Verify context is cleaned up after run assert "pydantic_ai_agent" not in scope._contexts -def test_context_cleanup_after_run_sync(sentry_init, test_agent): +def test_context_cleanup_after_run_sync(sentry_init, get_test_agent): """ Test that the pydantic_ai_agent context is properly cleaned up after sync agent execution. """ @@ -1053,6 +1137,7 @@ def test_context_cleanup_after_run_sync(sentry_init, test_agent): assert "pydantic_ai_agent" not in scope._contexts # Run the agent synchronously + test_agent = get_test_agent() test_agent.run_sync("Test input") # Verify context is cleaned up after run @@ -1060,7 +1145,7 @@ def test_context_cleanup_after_run_sync(sentry_init, test_agent): @pytest.mark.asyncio -async def test_context_cleanup_after_streaming(sentry_init, test_agent): +async def test_context_cleanup_after_streaming(sentry_init, get_test_agent): """ Test that the pydantic_ai_agent context is properly cleaned up after streaming execution. """ @@ -1075,6 +1160,7 @@ async def test_context_cleanup_after_streaming(sentry_init, test_agent): scope = sentry_sdk.get_current_scope() assert "pydantic_ai_agent" not in scope._contexts + test_agent = get_test_agent() # Run the agent with streaming async with test_agent.run_stream("Test input") as result: async for _ in result.stream_output(): @@ -1085,23 +1171,25 @@ async def test_context_cleanup_after_streaming(sentry_init, test_agent): @pytest.mark.asyncio -async def test_context_cleanup_on_error(sentry_init, test_agent): +async def test_context_cleanup_on_error(sentry_init, get_test_agent): """ Test that the pydantic_ai_agent context is cleaned up even when an error occurs. """ import sentry_sdk + sentry_init( + integrations=[PydanticAIIntegration()], + traces_sample_rate=1.0, + ) + + test_agent = get_test_agent() + # Create an agent with a tool that raises an error @test_agent.tool_plain def failing_tool() -> str: """A tool that always fails.""" raise ValueError("Tool error") - sentry_init( - integrations=[PydanticAIIntegration()], - traces_sample_rate=1.0, - ) - # Verify context is not set before run scope = sentry_sdk.get_current_scope() assert "pydantic_ai_agent" not in scope._contexts @@ -1117,7 +1205,7 @@ def failing_tool() -> str: @pytest.mark.asyncio -async def test_context_isolation_concurrent_agents(sentry_init, test_agent): +async def test_context_isolation_concurrent_agents(sentry_init, get_test_agent): """ Test that concurrent agent executions maintain isolated contexts. """ @@ -1150,6 +1238,7 @@ async def run_and_check_context(agent, agent_name): return agent_name + test_agent = get_test_agent() # Run both agents concurrently results = await asyncio.gather( run_and_check_context(test_agent, "agent1"), @@ -1403,22 +1492,23 @@ async def test_agent_data_from_scope(sentry_init, capture_events): @pytest.mark.asyncio async def test_available_tools_without_description( - sentry_init, capture_events, test_agent + sentry_init, capture_events, get_test_agent ): """ Test that available tools are captured even when description is missing. """ + sentry_init( + integrations=[PydanticAIIntegration()], + traces_sample_rate=1.0, + ) + + test_agent = get_test_agent() @test_agent.tool_plain def tool_without_desc(x: int) -> int: # No docstring = no description return x * 2 - sentry_init( - integrations=[PydanticAIIntegration()], - traces_sample_rate=1.0, - ) - events = capture_events() await test_agent.run("Use the tool with 5") @@ -1435,22 +1525,23 @@ def tool_without_desc(x: int) -> int: @pytest.mark.asyncio -async def test_output_with_tool_calls(sentry_init, capture_events, test_agent): +async def test_output_with_tool_calls(sentry_init, capture_events, get_test_agent): """ Test that tool calls in model response are captured correctly. """ - - @test_agent.tool_plain - def calc_tool(value: int) -> int: - """Calculate something.""" - return value + 10 - sentry_init( integrations=[PydanticAIIntegration()], traces_sample_rate=1.0, send_default_pii=True, ) + test_agent = get_test_agent() + + @test_agent.tool_plain + def calc_tool(value: int) -> int: + """Calculate something.""" + return value + 10 + events = capture_events() await test_agent.run("Use calc_tool with 5") @@ -1637,7 +1728,6 @@ async def test_input_messages_error_handling(sentry_init, capture_events): Test that _set_input_messages handles errors gracefully. """ import sentry_sdk - from sentry_sdk.integrations.pydantic_ai.spans.ai_client import _set_input_messages sentry_init( integrations=[PydanticAIIntegration()], @@ -1791,7 +1881,6 @@ async def test_message_parts_with_list_content(sentry_init, capture_events): """ import sentry_sdk from unittest.mock import MagicMock - from sentry_sdk.integrations.pydantic_ai.spans.ai_client import _set_input_messages sentry_init( integrations=[PydanticAIIntegration()], @@ -1898,7 +1987,6 @@ async def test_message_with_system_prompt_part(sentry_init, capture_events): """ import sentry_sdk from unittest.mock import MagicMock - from sentry_sdk.integrations.pydantic_ai.spans.ai_client import _set_input_messages from pydantic_ai import messages sentry_init( @@ -1935,7 +2023,6 @@ async def test_message_with_instructions(sentry_init, capture_events): """ import sentry_sdk from unittest.mock import MagicMock - from sentry_sdk.integrations.pydantic_ai.spans.ai_client import _set_input_messages sentry_init( integrations=[PydanticAIIntegration()], @@ -1970,7 +2057,6 @@ async def test_set_input_messages_without_prompts(sentry_init, capture_events): Test that _set_input_messages respects _should_send_prompts(). """ import sentry_sdk - from sentry_sdk.integrations.pydantic_ai.spans.ai_client import _set_input_messages sentry_init( integrations=[PydanticAIIntegration(include_prompts=False)], diff --git a/tests/integrations/pymongo/test_pymongo.py b/tests/integrations/pymongo/test_pymongo.py index 0669f73c30..b57061b0a0 100644 --- a/tests/integrations/pymongo/test_pymongo.py +++ b/tests/integrations/pymongo/test_pymongo.py @@ -52,11 +52,13 @@ def test_transactions(sentry_init, capture_events, mongo_server, with_pii): 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 @@ -136,6 +138,7 @@ def test_breadcrumbs(sentry_init, capture_events, mongo_server, with_pii): 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), diff --git a/tests/integrations/pyreqwest/__init__.py b/tests/integrations/pyreqwest/__init__.py new file mode 100644 index 0000000000..dfdd787852 --- /dev/null +++ b/tests/integrations/pyreqwest/__init__.py @@ -0,0 +1,9 @@ +import os +import sys +import pytest + +pytest.importorskip("pyreqwest") + +# Load `pyreqwest_helpers` into the module search path to test request source path names relative to module. See +# `test_request_source_with_module_in_search_path` +sys.path.insert(0, os.path.join(os.path.dirname(__file__))) diff --git a/tests/integrations/pyreqwest/pyreqwest_helpers/__init__.py b/tests/integrations/pyreqwest/pyreqwest_helpers/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/integrations/pyreqwest/pyreqwest_helpers/helpers.py b/tests/integrations/pyreqwest/pyreqwest_helpers/helpers.py new file mode 100644 index 0000000000..3abc554522 --- /dev/null +++ b/tests/integrations/pyreqwest/pyreqwest_helpers/helpers.py @@ -0,0 +1,2 @@ +def get_request_with_client(client, url): + client.get(url).build().send() diff --git a/tests/integrations/pyreqwest/test_pyreqwest.py b/tests/integrations/pyreqwest/test_pyreqwest.py new file mode 100644 index 0000000000..ad20e2b08a --- /dev/null +++ b/tests/integrations/pyreqwest/test_pyreqwest.py @@ -0,0 +1,484 @@ +import datetime +import os +from contextlib import contextmanager +from http.server import BaseHTTPRequestHandler, HTTPServer +from threading import Thread +from unittest import mock +import pytest + +from pyreqwest.client import ClientBuilder, SyncClientBuilder +from pyreqwest.simple.request import pyreqwest_get as async_pyreqwest_get +from pyreqwest.simple.sync_request import pyreqwest_get as sync_pyreqwest_get + +import sentry_sdk +from sentry_sdk import start_transaction +from sentry_sdk.consts import MATCH_ALL, SPANDATA +from sentry_sdk.integrations.pyreqwest import PyreqwestIntegration +from tests.conftest import get_free_port + + +class PyreqwestMockHandler(BaseHTTPRequestHandler): + captured_requests = [] + + def do_GET(self) -> None: + self.captured_requests.append( + { + "path": self.path, + "headers": {k.lower(): v for k, v in self.headers.items()}, + } + ) + + code = 200 + if "/status/" in self.path: + try: + code = int(self.path.split("/")[-1]) + except (ValueError, IndexError): + code = 200 + + self.send_response(code) + self.end_headers() + self.wfile.write(b"OK") + + def log_message(self, format: str, *args: object) -> None: + pass + + +@pytest.fixture(scope="module") +def server_port(): + port = get_free_port() + server = HTTPServer(("localhost", port), PyreqwestMockHandler) + thread = Thread(target=server.serve_forever) + thread.daemon = True + thread.start() + yield port + server.shutdown() + + +@pytest.fixture(autouse=True) +def clear_captured_requests(): + PyreqwestMockHandler.captured_requests.clear() + + +def test_sync_client_spans(sentry_init, capture_events, server_port): + sentry_init(integrations=[PyreqwestIntegration()], traces_sample_rate=1.0) + events = capture_events() + + url = f"http://localhost:{server_port}/hello?q=test#frag" + with start_transaction(name="test_transaction"): + client = SyncClientBuilder().build() + response = client.get(url).build().send() + assert response.status == 200 + + (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" + + +@pytest.mark.asyncio +async def test_async_client_spans(sentry_init, capture_events, server_port): + sentry_init(integrations=[PyreqwestIntegration()], traces_sample_rate=1.0) + events = capture_events() + + url = f"http://localhost:{server_port}/hello" + async with ClientBuilder().build() as client: + with start_transaction(name="test_transaction"): + response = await client.get(url).build().send() + assert response.status == 200 + + (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" + + +def test_sync_simple_request_spans(sentry_init, capture_events, server_port): + sentry_init(integrations=[PyreqwestIntegration()], traces_sample_rate=1.0) + events = capture_events() + + url = f"http://localhost:{server_port}/hello-simple" + with start_transaction(name="test_transaction"): + response = sync_pyreqwest_get(url).send() + assert response.status == 200 + + (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" + + +@pytest.mark.asyncio +async def test_async_simple_request_spans(sentry_init, capture_events, server_port): + sentry_init(integrations=[PyreqwestIntegration()], traces_sample_rate=1.0) + events = capture_events() + + url = f"http://localhost:{server_port}/hello-simple-async" + with start_transaction(name="test_transaction"): + response = await async_pyreqwest_get(url).send() + assert response.status == 200 + + (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" + + +def test_span_origin(sentry_init, capture_events, server_port): + sentry_init(integrations=[PyreqwestIntegration()], traces_sample_rate=1.0) + events = capture_events() + + url = f"http://localhost:{server_port}/origin" + with start_transaction(name="test_transaction"): + client = SyncClientBuilder().build() + client.get(url).build().send() + + (event,) = events + assert event["spans"][0]["origin"] == "auto.http.pyreqwest" + + +def test_outgoing_trace_headers(sentry_init, server_port): + sentry_init( + integrations=[PyreqwestIntegration()], + traces_sample_rate=1.0, + trace_propagation_targets=["localhost"], + ) + + url = f"http://localhost:{server_port}/trace" + 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 "sentry-trace" in headers + assert headers["sentry-trace"].startswith("01234567890123456789012345678901") + assert "baggage" in headers + assert "sentry-trace_id=01234567890123456789012345678901" in headers["baggage"] + + +def test_outgoing_trace_headers_append_to_baggage(sentry_init, server_port): + sentry_init( + integrations=[PyreqwestIntegration()], + traces_sample_rate=1.0, + trace_propagation_targets=["localhost"], + release="d08ebdb9309e1b004c6f52202de58a09c2268e42", + ) + + url = f"http://localhost:{server_port}/baggage" + + 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 "sentry-sample_rand=0.500000" in baggage + assert "sentry-environment=production" in baggage + assert "sentry-release=d08ebdb9309e1b004c6f52202de58a09c2268e42" in baggage + assert "sentry-transaction=/interactions/other-dogs/new-dog" in baggage + assert "sentry-sample_rate=1.0" in baggage + assert "sentry-sampled=true" in baggage + + +@pytest.mark.parametrize( + "trace_propagation_targets,trace_propagated", + [ + [None, False], + [[], False], + [[MATCH_ALL], True], + [["localhost"], True], + [[r"https?:\/\/[\w\-]+(\.[\w\-]+)+\.net"], False], + ], +) +def test_trace_propagation_targets( + sentry_init, server_port, trace_propagation_targets, trace_propagated +): + sentry_init( + integrations=[PyreqwestIntegration()], + trace_propagation_targets=trace_propagation_targets, + traces_sample_rate=1.0, + ) + + url = f"http://localhost:{server_port}/propagation" + + with start_transaction(): + client = SyncClientBuilder().build() + client.get(url).build().send() + + assert len(PyreqwestMockHandler.captured_requests) == 1 + headers = PyreqwestMockHandler.captured_requests[0]["headers"] + + if trace_propagated: + assert "sentry-trace" in headers + else: + assert "sentry-trace" not in headers + + +@pytest.mark.tests_internal_exceptions +def test_omit_url_data_if_parsing_fails(sentry_init, capture_events, server_port): + sentry_init( + integrations=[PyreqwestIntegration()], + traces_sample_rate=1.0, + ) + events = capture_events() + + url = f"http://localhost:{server_port}/parse-fail" + + 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() + + (event,) = events + span = event["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"] + + +def test_request_source_disabled(sentry_init, capture_events, server_port): + sentry_init( + integrations=[PyreqwestIntegration()], + traces_sample_rate=1.0, + enable_http_request_source=False, + http_request_source_threshold_ms=0, + ) + events = capture_events() + + url = f"http://localhost:{server_port}/hello" + + with start_transaction(name="test_transaction"): + client = SyncClientBuilder().build() + client.get(url).build().send() + + (event,) = events + span = event["spans"][0] + 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( + sentry_init, capture_events, server_port, enable_http_request_source +): + sentry_options = { + "integrations": [PyreqwestIntegration()], + "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 = f"http://localhost:{server_port}/hello" + + with start_transaction(name="test_transaction"): + client = SyncClientBuilder().build() + client.get(url).build().send() + + (event,) = events + span = event["spans"][0] + 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(sentry_init, capture_events, server_port): + sentry_init( + integrations=[PyreqwestIntegration()], + traces_sample_rate=1.0, + enable_http_request_source=True, + http_request_source_threshold_ms=0, + ) + events = capture_events() + + url = f"http://localhost:{server_port}/hello" + + with start_transaction(name="test_transaction"): + client = SyncClientBuilder().build() + client.get(url).build().send() + + (event,) = events + span = event["spans"][0] + data = span.get("data", {}) + + 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" + ) + + is_relative_path = data.get(SPANDATA.CODE_FILEPATH)[0] != os.sep + assert is_relative_path + + assert data.get(SPANDATA.CODE_FUNCTION) == "test_request_source" + + +def test_request_source_with_module_in_search_path( + sentry_init, capture_events, server_port +): + sentry_init( + integrations=[PyreqwestIntegration()], + traces_sample_rate=1.0, + enable_http_request_source=True, + http_request_source_threshold_ms=0, + ) + events = capture_events() + + url = f"http://localhost:{server_port}/hello" + + with start_transaction(name="test_transaction"): + from pyreqwest_helpers.helpers import get_request_with_client + + client = SyncClientBuilder().build() + get_request_with_client(client, url) + + (event,) = events + span = event["spans"][0] + data = span.get("data", {}) + + 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" + + 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" + + +def test_no_request_source_if_duration_too_short( + sentry_init, capture_events, server_port +): + sentry_init( + integrations=[PyreqwestIntegration()], + traces_sample_rate=1.0, + enable_http_request_source=True, + http_request_source_threshold_ms=100, + ) + events = capture_events() + + url = f"http://localhost:{server_port}/hello" + + with start_transaction(name="test_transaction"): + + @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() + + (event,) = events + span = event["spans"][-1] + 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( + sentry_init, capture_events, server_port +): + sentry_init( + integrations=[PyreqwestIntegration()], + traces_sample_rate=1.0, + enable_http_request_source=True, + http_request_source_threshold_ms=100, + ) + events = capture_events() + + url = f"http://localhost:{server_port}/hello" + + with start_transaction(name="test_transaction"): + + @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() + + (event,) = events + span = event["spans"][-1] + 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 diff --git a/tests/integrations/redis/test_redis.py b/tests/integrations/redis/test_redis.py index 1861e7116f..84c5699d14 100644 --- a/tests/integrations/redis/test_redis.py +++ b/tests/integrations/redis/test_redis.py @@ -262,6 +262,7 @@ def test_db_connection_attributes_client(sentry_init, capture_events): 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 @@ -288,6 +289,7 @@ def test_db_connection_attributes_pipeline(sentry_init, capture_events): 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 diff --git a/tests/integrations/sqlalchemy/test_sqlalchemy.py b/tests/integrations/sqlalchemy/test_sqlalchemy.py index d2a31a55d5..7c7ce3d845 100644 --- a/tests/integrations/sqlalchemy/test_sqlalchemy.py +++ b/tests/integrations/sqlalchemy/test_sqlalchemy.py @@ -127,6 +127,7 @@ class Address(Base): 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"] @@ -201,6 +202,7 @@ class Address(Base): 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"] @@ -301,7 +303,7 @@ def test_engine_name_not_string(sentry_init): def test_query_source_disabled(sentry_init, capture_events): sentry_options = { "integrations": [SqlalchemyIntegration()], - "enable_tracing": True, + "traces_sample_rate": 1.0, "enable_db_query_source": False, "db_query_source_threshold_ms": 0, } @@ -352,7 +354,7 @@ class Person(Base): def test_query_source_enabled(sentry_init, capture_events, enable_db_query_source): sentry_options = { "integrations": [SqlalchemyIntegration()], - "enable_tracing": True, + "traces_sample_rate": 1.0, "db_query_source_threshold_ms": 0, } if enable_db_query_source is not None: @@ -403,7 +405,7 @@ class Person(Base): def test_query_source(sentry_init, capture_events): sentry_init( integrations=[SqlalchemyIntegration()], - enable_tracing=True, + traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, ) @@ -468,7 +470,7 @@ def test_query_source_with_module_in_search_path(sentry_init, capture_events): """ sentry_init( integrations=[SqlalchemyIntegration()], - enable_tracing=True, + traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=0, ) @@ -531,7 +533,7 @@ class Person(Base): def test_no_query_source_if_duration_too_short(sentry_init, capture_events): sentry_init( integrations=[SqlalchemyIntegration()], - enable_tracing=True, + traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=100, ) @@ -597,7 +599,7 @@ def __exit__(self, type, value, traceback): def test_query_source_if_duration_over_threshold(sentry_init, capture_events): sentry_init( integrations=[SqlalchemyIntegration()], - enable_tracing=True, + traces_sample_rate=1.0, enable_db_query_source=True, db_query_source_threshold_ms=100, ) diff --git a/tests/integrations/wsgi/test_wsgi.py b/tests/integrations/wsgi/test_wsgi.py index 1878be4866..a95a1d63fa 100644 --- a/tests/integrations/wsgi/test_wsgi.py +++ b/tests/integrations/wsgi/test_wsgi.py @@ -6,7 +6,11 @@ import sentry_sdk from sentry_sdk import capture_message -from sentry_sdk.integrations.wsgi import SentryWsgiMiddleware, _ScopedResponse +from sentry_sdk.integrations.wsgi import ( + SentryWsgiMiddleware, + _ScopedResponse, + get_request_url, +) @pytest.fixture @@ -135,26 +139,50 @@ 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.") - sentry_init(send_default_pii=True, traces_sample_rate=1.0) + sentry_init( + send_default_pii=True, + traces_sample_rate=1.0, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) app = SentryWsgiMiddleware(dogpark) client = Client(app) - events = capture_events() + + if span_streaming: + items = capture_items("event", "span") + else: + events = capture_events() with pytest.raises(ValueError): client.get("http://dogs.are.great/sit/stay/rollover/") - error_event, envelope = events + 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 error_event["transaction"] == "generic WSGI request" - assert error_event["transaction"] == "generic WSGI request" assert error_event["contexts"]["trace"]["op"] == "http.server" assert error_event["exception"]["values"][0]["type"] == "ValueError" assert error_event["exception"]["values"][0]["mechanism"]["type"] == "wsgi" @@ -164,75 +192,145 @@ def dogpark(environ, start_response): == "Fetch aborted. The ball was not returned." ) - assert envelope["type"] == "transaction" + 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"] + # 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"] +@pytest.mark.parametrize("span_streaming", [True, False]) def test_transaction_no_error( sentry_init, capture_events, + capture_items, DictionaryContaining, # noqa:N803 + span_streaming, ): def dogpark(environ, start_response): start_response("200 OK", []) return ["Go get the ball! Good dog!"] - sentry_init(send_default_pii=True, traces_sample_rate=1.0) + sentry_init( + send_default_pii=True, + traces_sample_rate=1.0, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) app = SentryWsgiMiddleware(dogpark) client = Client(app) - events = capture_events() + + if span_streaming: + items = capture_items("span") + else: + events = capture_events() client.get("/dogs/are/great/") - envelope = events[0] + sentry_sdk.flush() - 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/"} - ) + 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.span.source"] == "route" + assert span["attributes"]["http.request.method"] == "GET" + assert span["attributes"]["url.full"] == "http://localhost/dogs/are/great/" + assert span["attributes"]["http.response.status_code"] == 200 + assert span["status"] == "ok" + else: + envelope = events[0] + + 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/"} + ) +@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") raise ValueError("Fetch aborted. The ball was not returned.") - sentry_init(traces_sample_rate=1.0) + sentry_init( + traces_sample_rate=1.0, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) app = SentryWsgiMiddleware(dogpark) client = Client(app) - events = capture_events() + + if span_streaming: + items = capture_items("event", "span") + else: + events = capture_events() with pytest.raises(ValueError): client.get("http://dogs.are.great/sit/stay/rollover/") - msg_event, error_event, transaction_event = events + sentry_sdk.flush() + + if span_streaming: + msg_event, error_event, span_item = 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_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"] + ) + 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"] + == error_event["contexts"]["trace"]["trace_id"] + == transaction_event["contexts"]["trace"]["trace_id"] + ) def test_has_trace_if_performance_disabled( @@ -260,18 +358,30 @@ 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") raise ValueError("Fetch aborted. The ball was not returned.") - sentry_init(traces_sample_rate=1.0) + sentry_init( + traces_sample_rate=1.0, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) app = SentryWsgiMiddleware(dogpark) client = Client(app) - events = capture_events() + + if span_streaming: + items = capture_items("event", "span") + else: + events = capture_events() trace_id = "582b43a4192642f0b136d5159a501701" sentry_trace_header = "{}-{}-{}".format(trace_id, "6e8f22c393e68f19", 1) @@ -282,20 +392,29 @@ def dogpark(environ, start_response): headers={"sentry-trace": sentry_trace_header}, ) - msg_event, error_event, transaction_event = events + sentry_sdk.flush() - assert msg_event["contexts"]["trace"] - assert "trace_id" in msg_event["contexts"]["trace"] + if span_streaming: + msg_event, error_event, span_item = items - assert error_event["contexts"]["trace"] - assert "trace_id" in error_event["contexts"]["trace"] + 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 transaction_event["contexts"]["trace"] - assert "trace_id" in transaction_event["contexts"]["trace"] + assert msg_event["contexts"]["trace"] + assert "trace_id" in msg_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 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 def test_trace_from_headers_if_performance_disabled( @@ -331,37 +450,65 @@ 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", []) return ["Go get the ball! Good dog!"] traces_sampler = mock.Mock(return_value=True) - sentry_init(send_default_pii=True, traces_sampler=traces_sampler) + sentry_init( + send_default_pii=True, + traces_sampler=traces_sampler, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) app = SentryWsgiMiddleware(app) client = Client(app) client.get("/dogs/are/great/") - traces_sampler.assert_any_call( - DictionaryContaining( - { - "wsgi_environ": DictionaryContaining( - { - "PATH_INFO": "/dogs/are/great/", - "REQUEST_METHOD": "GET", - }, - ), - } + if span_streaming: + traces_sampler.assert_any_call( + DictionaryContaining( + { + "span_context": DictionaryContaining( + { + "name": "generic WSGI request", + }, + ), + "wsgi_environ": DictionaryContaining( + { + "PATH_INFO": "/dogs/are/great/", + "REQUEST_METHOD": "GET", + }, + ), + } + ) + ) + else: + traces_sampler.assert_any_call( + DictionaryContaining( + { + "wsgi_environ": DictionaryContaining( + { + "PATH_INFO": "/dogs/are/great/", + "REQUEST_METHOD": "GET", + }, + ), + } + ) ) - ) +@pytest.mark.parametrize("span_streaming", [True, False]) def test_session_mode_defaults_to_request_mode_in_wsgi_handler( - capture_envelopes, sentry_init + capture_envelopes, sentry_init, span_streaming ): """ Test that ensures that even though the default `session_mode` for @@ -374,7 +521,13 @@ def app(environ, start_response): return ["Go get the ball! Good dog!"] traces_sampler = mock.Mock(return_value=True) - sentry_init(send_default_pii=True, traces_sampler=traces_sampler) + sentry_init( + send_default_pii=True, + traces_sampler=traces_sampler, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) app = SentryWsgiMiddleware(app) envelopes = capture_envelopes() @@ -384,7 +537,11 @@ def app(environ, start_response): sentry_sdk.flush() - sess = envelopes[1] + session_envelopes = [ + e for e in envelopes if any(item.type == "sessions" for item in e.items) + ] + assert len(session_envelopes) == 1 + sess = session_envelopes[0] assert len(sess.items) == 1 sess_event = sess.items[0].payload.json @@ -393,7 +550,10 @@ def app(environ, start_response): assert aggregates[0]["exited"] == 1 -def test_auto_session_tracking_with_aggregates(sentry_init, capture_envelopes): +@pytest.mark.parametrize("span_streaming", [True, False]) +def test_auto_session_tracking_with_aggregates( + sentry_init, capture_envelopes, span_streaming +): """ Test for correct session aggregates in auto session tracking. """ @@ -406,7 +566,13 @@ def sample_app(environ, start_response): return ["Go get the ball! Good dog!"] traces_sampler = mock.Mock(return_value=True) - sentry_init(send_default_pii=True, traces_sampler=traces_sampler) + sentry_init( + send_default_pii=True, + traces_sampler=traces_sampler, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) app = SentryWsgiMiddleware(sample_app) envelopes = capture_envelopes() assert len(envelopes) == 0 @@ -423,14 +589,21 @@ def sample_app(environ, start_response): count_item_types = Counter() for envelope in envelopes: - count_item_types[envelope.items[0].type] += 1 + for item in envelope.items: + count_item_types[item.type] += 1 - assert count_item_types["transaction"] == 3 + if span_streaming: + assert count_item_types["span"] == 3 + else: + assert count_item_types["transaction"] == 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_envelopes = [ + e for e in envelopes if any(item.type == "sessions" for item in e.items) + ] + assert len(session_envelopes) == 1 + session_aggregates = session_envelopes[0].items[0].payload.json["aggregates"] assert session_aggregates[0]["exited"] == 2 assert session_aggregates[0]["crashed"] == 1 assert len(session_aggregates) == 1 @@ -463,43 +636,73 @@ def test_app(environ, start_response): assert len(profiles) == 1 -def test_span_origin_manual(sentry_init, capture_events): +@pytest.mark.parametrize("span_streaming", [True, False]) +def test_span_origin_manual(sentry_init, capture_events, capture_items, span_streaming): def dogpark(environ, start_response): start_response("200 OK", []) return ["Go get the ball! Good dog!"] - sentry_init(send_default_pii=True, traces_sample_rate=1.0) + sentry_init( + send_default_pii=True, + traces_sample_rate=1.0, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) app = SentryWsgiMiddleware(dogpark) - events = capture_events() + if span_streaming: + items = capture_items("span") + else: + events = capture_events() client = Client(app) client.get("/dogs/are/great/") - (event,) = events + sentry_sdk.flush() - assert event["contexts"]["trace"]["origin"] == "manual" + if span_streaming: + assert len(items) == 1 + assert items[0].payload["attributes"]["sentry.origin"] == "manual" + else: + (event,) = events + assert event["contexts"]["trace"]["origin"] == "manual" -def test_span_origin_custom(sentry_init, capture_events): +@pytest.mark.parametrize("span_streaming", [True, False]) +def test_span_origin_custom(sentry_init, capture_events, capture_items, span_streaming): def dogpark(environ, start_response): start_response("200 OK", []) return ["Go get the ball! Good dog!"] - sentry_init(send_default_pii=True, traces_sample_rate=1.0) + sentry_init( + send_default_pii=True, + traces_sample_rate=1.0, + _experiments={ + "trace_lifecycle": "stream" if span_streaming else "static", + }, + ) app = SentryWsgiMiddleware( dogpark, span_origin="auto.dogpark.deluxe", ) - events = capture_events() + if span_streaming: + items = capture_items("span") + else: + events = capture_events() client = Client(app) client.get("/dogs/are/great/") - (event,) = events + sentry_sdk.flush() - assert event["contexts"]["trace"]["origin"] == "auto.dogpark.deluxe" + 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" @pytest.mark.parametrize( @@ -547,3 +750,94 @@ def app(environ, start_response): assert isinstance(result, _ScopedResponse) else: assert result is response_mock + + +@pytest.mark.parametrize( + "environ,use_x_forwarded_for,expected_url", + [ + # Without use_x_forwarded_for, wsgi.url_scheme is used + ( + { + "wsgi.url_scheme": "http", + "SERVER_NAME": "example.com", + "SERVER_PORT": "80", + "PATH_INFO": "/test", + "HTTP_X_FORWARDED_PROTO": "https", + }, + False, + "http://example.com/test", + ), + # With use_x_forwarded_for, HTTP_X_FORWARDED_PROTO is respected + ( + { + "wsgi.url_scheme": "http", + "SERVER_NAME": "example.com", + "SERVER_PORT": "80", + "PATH_INFO": "/test", + "HTTP_X_FORWARDED_PROTO": "https", + }, + True, + "https://example.com/test", + ), + # With use_x_forwarded_for but no forwarded proto, wsgi.url_scheme is used + ( + { + "wsgi.url_scheme": "http", + "SERVER_NAME": "example.com", + "SERVER_PORT": "80", + "PATH_INFO": "/test", + }, + True, + "http://example.com/test", + ), + # Forwarded host with default https port is stripped using forwarded proto + ( + { + "wsgi.url_scheme": "http", + "SERVER_NAME": "internal", + "SERVER_PORT": "80", + "PATH_INFO": "/test", + "HTTP_X_FORWARDED_PROTO": "https", + "HTTP_X_FORWARDED_HOST": "example.com:443", + }, + True, + "https://example.com/test", + ), + # Forwarded host with non-default port is preserved + ( + { + "wsgi.url_scheme": "http", + "SERVER_NAME": "internal", + "SERVER_PORT": "80", + "PATH_INFO": "/test", + "HTTP_X_FORWARDED_PROTO": "https", + "HTTP_X_FORWARDED_HOST": "example.com:8443", + }, + True, + "https://example.com:8443/test", + ), + # Forwarded proto with HTTP_HOST (no forwarded host) strips default port + ( + { + "wsgi.url_scheme": "http", + "HTTP_HOST": "example.com:443", + "SERVER_NAME": "internal", + "SERVER_PORT": "80", + "PATH_INFO": "/test", + "HTTP_X_FORWARDED_PROTO": "https", + }, + True, + "https://example.com/test", + ), + ], + ids=[ + "ignores_forwarded_proto_when_disabled", + "respects_forwarded_proto_when_enabled", + "falls_back_to_url_scheme_when_no_forwarded_proto", + "strips_default_https_port_from_forwarded_host", + "preserves_non_default_port_on_forwarded_host", + "strips_default_port_from_http_host_with_forwarded_proto", + ], +) +def test_get_request_url_x_forwarded_proto(environ, use_x_forwarded_for, expected_url): + assert get_request_url(environ, use_x_forwarded_for) == expected_url diff --git a/tests/test_ai_monitoring.py b/tests/test_ai_monitoring.py index c9f5c5cdcd..406ac05edb 100644 --- a/tests/test_ai_monitoring.py +++ b/tests/test_ai_monitoring.py @@ -814,6 +814,71 @@ def test_redacts_blobs_in_multiple_messages(self): 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 = [ diff --git a/tests/test_basics.py b/tests/test_basics.py index da836462d8..afbbf929f2 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -1092,7 +1092,7 @@ def test_classmethod_instance_tracing(sentry_init, capture_events): def test_last_event_id(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) assert last_event_id() is None @@ -1102,7 +1102,7 @@ def test_last_event_id(sentry_init): def test_last_event_id_transaction(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) assert last_event_id() is None @@ -1113,7 +1113,7 @@ def test_last_event_id_transaction(sentry_init): def test_last_event_id_scope(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) # Should not crash with isolation_scope() as scope: diff --git a/tests/test_client.py b/tests/test_client.py index 96ebcf1790..7e6a474016 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -26,9 +26,22 @@ from sentry_sdk.spotlight import DEFAULT_SPOTLIGHT_URL from sentry_sdk.utils import capture_internal_exception from sentry_sdk.integrations.executing import ExecutingIntegration -from sentry_sdk.transport import Transport +from sentry_sdk.integrations.asyncio import AsyncioIntegration +from sentry_sdk.transport import Transport, AsyncHttpTransport from sentry_sdk.serializer import MAX_DATABAG_BREADTH from sentry_sdk.consts import DEFAULT_MAX_BREADCRUMBS, DEFAULT_MAX_VALUE_LENGTH +from sentry_sdk._compat import PY38 + +try: + import gevent # noqa: F401 + + running_under_gevent = True +except ImportError: + running_under_gevent = False + +skip_under_gevent = pytest.mark.skipif( + running_under_gevent, reason="Async tests not compatible with gevent" +) from typing import TYPE_CHECKING @@ -43,6 +56,241 @@ reason="Since Python 3.13, `FrameLocalsProxy` skips items of `locals()` that have non-`str` keys; this is a CPython implementation detail: https://github.com/python/cpython/blame/7b413952e817ae87bfda2ac85dd84d30a6ce743b/Objects/frameobject.c#L148", ) +PROXY_TESTCASES = [ + { + "dsn": "http://foo@sentry.io/123", + "env_http_proxy": None, + "env_https_proxy": None, + "arg_http_proxy": "http://localhost/123", + "arg_https_proxy": None, + "expected_proxy_scheme": "http", + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": None, + "env_https_proxy": None, + "arg_http_proxy": "https://localhost/123", + "arg_https_proxy": None, + "expected_proxy_scheme": "https", + }, + { + "dsn": "http://foo@sentry.io/123", + "env_http_proxy": None, + "env_https_proxy": None, + "arg_http_proxy": "http://localhost/123", + "arg_https_proxy": "https://localhost/123", + "expected_proxy_scheme": "http", + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": None, + "env_https_proxy": None, + "arg_http_proxy": "http://localhost/123", + "arg_https_proxy": "https://localhost/123", + "expected_proxy_scheme": "https", + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": None, + "env_https_proxy": None, + "arg_http_proxy": "http://localhost/123", + "arg_https_proxy": None, + "expected_proxy_scheme": "http", + }, + { + "dsn": "http://foo@sentry.io/123", + "env_http_proxy": None, + "env_https_proxy": None, + "arg_http_proxy": None, + "arg_https_proxy": None, + "expected_proxy_scheme": None, + }, + { + "dsn": "http://foo@sentry.io/123", + "env_http_proxy": "http://localhost/123", + "env_https_proxy": None, + "arg_http_proxy": None, + "arg_https_proxy": None, + "expected_proxy_scheme": "http", + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": None, + "env_https_proxy": "https://localhost/123", + "arg_http_proxy": None, + "arg_https_proxy": None, + "expected_proxy_scheme": "https", + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": "http://localhost/123", + "env_https_proxy": None, + "arg_http_proxy": None, + "arg_https_proxy": None, + "expected_proxy_scheme": "http", + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": "http://localhost/123", + "env_https_proxy": "https://localhost/123", + "arg_http_proxy": "", + "arg_https_proxy": "", + "expected_proxy_scheme": None, + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": "http://localhost/123", + "env_https_proxy": "https://localhost/123", + "arg_http_proxy": None, + "arg_https_proxy": None, + "expected_proxy_scheme": "https", + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": "http://localhost/123", + "env_https_proxy": None, + "arg_http_proxy": None, + "arg_https_proxy": None, + "expected_proxy_scheme": "http", + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": "http://localhost/123", + "env_https_proxy": "https://localhost/123", + "arg_http_proxy": None, + "arg_https_proxy": "", + "expected_proxy_scheme": "http", + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": "http://localhost/123", + "env_https_proxy": "https://localhost/123", + "arg_http_proxy": "", + "arg_https_proxy": None, + "expected_proxy_scheme": "https", + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": None, + "env_https_proxy": "https://localhost/123", + "arg_http_proxy": None, + "arg_https_proxy": "", + "expected_proxy_scheme": None, + }, + { + "dsn": "http://foo@sentry.io/123", + "env_http_proxy": "http://localhost/123", + "env_https_proxy": "https://localhost/123", + "arg_http_proxy": None, + "arg_https_proxy": None, + "expected_proxy_scheme": "http", + }, + # NO_PROXY testcases + { + "dsn": "http://foo@sentry.io/123", + "env_http_proxy": "http://localhost/123", + "env_https_proxy": None, + "env_no_proxy": "sentry.io,example.com", + "arg_http_proxy": None, + "arg_https_proxy": None, + "expected_proxy_scheme": None, + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": None, + "env_https_proxy": "https://localhost/123", + "env_no_proxy": "example.com,sentry.io", + "arg_http_proxy": None, + "arg_https_proxy": None, + "expected_proxy_scheme": None, + }, + { + "dsn": "http://foo@sentry.io/123", + "env_http_proxy": None, + "env_https_proxy": None, + "env_no_proxy": "sentry.io,example.com", + "arg_http_proxy": "http://localhost/123", + "arg_https_proxy": None, + "expected_proxy_scheme": "http", + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": None, + "env_https_proxy": None, + "env_no_proxy": "sentry.io,example.com", + "arg_http_proxy": None, + "arg_https_proxy": "https://localhost/123", + "expected_proxy_scheme": "https", + }, + { + "dsn": "https://foo@sentry.io/123", + "env_http_proxy": None, + "env_https_proxy": None, + "env_no_proxy": "sentry.io,example.com", + "arg_http_proxy": None, + "arg_https_proxy": "https://localhost/123", + "expected_proxy_scheme": "https", + "arg_proxy_headers": {"Test-Header": "foo-bar"}, + }, +] + +SOCKS_PROXY_TESTCASES = [ + { + "dsn": "https://foo@sentry.io/123", + "arg_http_proxy": "http://localhost/123", + "arg_https_proxy": None, + "should_be_socks_proxy": False, + }, + { + "dsn": "https://foo@sentry.io/123", + "arg_http_proxy": "socks4a://localhost/123", + "arg_https_proxy": None, + "should_be_socks_proxy": True, + }, + { + "dsn": "https://foo@sentry.io/123", + "arg_http_proxy": "socks4://localhost/123", + "arg_https_proxy": None, + "should_be_socks_proxy": True, + }, + { + "dsn": "https://foo@sentry.io/123", + "arg_http_proxy": "socks5h://localhost/123", + "arg_https_proxy": None, + "should_be_socks_proxy": True, + }, + { + "dsn": "https://foo@sentry.io/123", + "arg_http_proxy": "socks5://localhost/123", + "arg_https_proxy": None, + "should_be_socks_proxy": True, + }, + { + "dsn": "https://foo@sentry.io/123", + "arg_http_proxy": None, + "arg_https_proxy": "socks4a://localhost/123", + "should_be_socks_proxy": True, + }, + { + "dsn": "https://foo@sentry.io/123", + "arg_http_proxy": None, + "arg_https_proxy": "socks4://localhost/123", + "should_be_socks_proxy": True, + }, + { + "dsn": "https://foo@sentry.io/123", + "arg_http_proxy": None, + "arg_https_proxy": "socks5h://localhost/123", + "should_be_socks_proxy": True, + }, + { + "dsn": "https://foo@sentry.io/123", + "arg_http_proxy": None, + "arg_https_proxy": "socks5://localhost/123", + "should_be_socks_proxy": True, + }, +] + class EnvelopeCapturedError(Exception): pass @@ -68,186 +316,7 @@ def test_transport_option(monkeypatch): assert str(Client(transport=transport).dsn) == dsn -@pytest.mark.parametrize( - "testcase", - [ - { - "dsn": "http://foo@sentry.io/123", - "env_http_proxy": None, - "env_https_proxy": None, - "arg_http_proxy": "http://localhost/123", - "arg_https_proxy": None, - "expected_proxy_scheme": "http", - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": None, - "env_https_proxy": None, - "arg_http_proxy": "https://localhost/123", - "arg_https_proxy": None, - "expected_proxy_scheme": "https", - }, - { - "dsn": "http://foo@sentry.io/123", - "env_http_proxy": None, - "env_https_proxy": None, - "arg_http_proxy": "http://localhost/123", - "arg_https_proxy": "https://localhost/123", - "expected_proxy_scheme": "http", - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": None, - "env_https_proxy": None, - "arg_http_proxy": "http://localhost/123", - "arg_https_proxy": "https://localhost/123", - "expected_proxy_scheme": "https", - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": None, - "env_https_proxy": None, - "arg_http_proxy": "http://localhost/123", - "arg_https_proxy": None, - "expected_proxy_scheme": "http", - }, - { - "dsn": "http://foo@sentry.io/123", - "env_http_proxy": None, - "env_https_proxy": None, - "arg_http_proxy": None, - "arg_https_proxy": None, - "expected_proxy_scheme": None, - }, - { - "dsn": "http://foo@sentry.io/123", - "env_http_proxy": "http://localhost/123", - "env_https_proxy": None, - "arg_http_proxy": None, - "arg_https_proxy": None, - "expected_proxy_scheme": "http", - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": None, - "env_https_proxy": "https://localhost/123", - "arg_http_proxy": None, - "arg_https_proxy": None, - "expected_proxy_scheme": "https", - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": "http://localhost/123", - "env_https_proxy": None, - "arg_http_proxy": None, - "arg_https_proxy": None, - "expected_proxy_scheme": "http", - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": "http://localhost/123", - "env_https_proxy": "https://localhost/123", - "arg_http_proxy": "", - "arg_https_proxy": "", - "expected_proxy_scheme": None, - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": "http://localhost/123", - "env_https_proxy": "https://localhost/123", - "arg_http_proxy": None, - "arg_https_proxy": None, - "expected_proxy_scheme": "https", - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": "http://localhost/123", - "env_https_proxy": None, - "arg_http_proxy": None, - "arg_https_proxy": None, - "expected_proxy_scheme": "http", - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": "http://localhost/123", - "env_https_proxy": "https://localhost/123", - "arg_http_proxy": None, - "arg_https_proxy": "", - "expected_proxy_scheme": "http", - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": "http://localhost/123", - "env_https_proxy": "https://localhost/123", - "arg_http_proxy": "", - "arg_https_proxy": None, - "expected_proxy_scheme": "https", - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": None, - "env_https_proxy": "https://localhost/123", - "arg_http_proxy": None, - "arg_https_proxy": "", - "expected_proxy_scheme": None, - }, - { - "dsn": "http://foo@sentry.io/123", - "env_http_proxy": "http://localhost/123", - "env_https_proxy": "https://localhost/123", - "arg_http_proxy": None, - "arg_https_proxy": None, - "expected_proxy_scheme": "http", - }, - # NO_PROXY testcases - { - "dsn": "http://foo@sentry.io/123", - "env_http_proxy": "http://localhost/123", - "env_https_proxy": None, - "env_no_proxy": "sentry.io,example.com", - "arg_http_proxy": None, - "arg_https_proxy": None, - "expected_proxy_scheme": None, - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": None, - "env_https_proxy": "https://localhost/123", - "env_no_proxy": "example.com,sentry.io", - "arg_http_proxy": None, - "arg_https_proxy": None, - "expected_proxy_scheme": None, - }, - { - "dsn": "http://foo@sentry.io/123", - "env_http_proxy": None, - "env_https_proxy": None, - "env_no_proxy": "sentry.io,example.com", - "arg_http_proxy": "http://localhost/123", - "arg_https_proxy": None, - "expected_proxy_scheme": "http", - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": None, - "env_https_proxy": None, - "env_no_proxy": "sentry.io,example.com", - "arg_http_proxy": None, - "arg_https_proxy": "https://localhost/123", - "expected_proxy_scheme": "https", - }, - { - "dsn": "https://foo@sentry.io/123", - "env_http_proxy": None, - "env_https_proxy": None, - "env_no_proxy": "sentry.io,example.com", - "arg_http_proxy": None, - "arg_https_proxy": "https://localhost/123", - "expected_proxy_scheme": "https", - "arg_proxy_headers": {"Test-Header": "foo-bar"}, - }, - ], -) +@pytest.mark.parametrize("testcase", PROXY_TESTCASES) @pytest.mark.parametrize( "http2", [True, False] if sys.version_info >= (3, 8) else [False] ) @@ -300,65 +369,7 @@ def test_proxy(monkeypatch, testcase, http2): assert proxy_headers == testcase["arg_proxy_headers"] -@pytest.mark.parametrize( - "testcase", - [ - { - "dsn": "https://foo@sentry.io/123", - "arg_http_proxy": "http://localhost/123", - "arg_https_proxy": None, - "should_be_socks_proxy": False, - }, - { - "dsn": "https://foo@sentry.io/123", - "arg_http_proxy": "socks4a://localhost/123", - "arg_https_proxy": None, - "should_be_socks_proxy": True, - }, - { - "dsn": "https://foo@sentry.io/123", - "arg_http_proxy": "socks4://localhost/123", - "arg_https_proxy": None, - "should_be_socks_proxy": True, - }, - { - "dsn": "https://foo@sentry.io/123", - "arg_http_proxy": "socks5h://localhost/123", - "arg_https_proxy": None, - "should_be_socks_proxy": True, - }, - { - "dsn": "https://foo@sentry.io/123", - "arg_http_proxy": "socks5://localhost/123", - "arg_https_proxy": None, - "should_be_socks_proxy": True, - }, - { - "dsn": "https://foo@sentry.io/123", - "arg_http_proxy": None, - "arg_https_proxy": "socks4a://localhost/123", - "should_be_socks_proxy": True, - }, - { - "dsn": "https://foo@sentry.io/123", - "arg_http_proxy": None, - "arg_https_proxy": "socks4://localhost/123", - "should_be_socks_proxy": True, - }, - { - "dsn": "https://foo@sentry.io/123", - "arg_http_proxy": None, - "arg_https_proxy": "socks5h://localhost/123", - "should_be_socks_proxy": True, - }, - { - "dsn": "https://foo@sentry.io/123", - "arg_http_proxy": None, - "arg_https_proxy": "socks5://localhost/123", - "should_be_socks_proxy": True, - }, - ], -) +@pytest.mark.parametrize("testcase", SOCKS_PROXY_TESTCASES) @pytest.mark.parametrize( "http2", [True, False] if sys.version_info >= (3, 8) else [False] ) @@ -1585,3 +1596,266 @@ def test_keep_alive(env_value, arg_value, expected_value): ) assert transport_cls.options["keep_alive"] is expected_value + + +@pytest.mark.parametrize("testcase", PROXY_TESTCASES) +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async transport requires Python 3.8+") +async def test_async_proxy(monkeypatch, testcase): + # These are just the same tests as the sync ones, but they need to be run in an event loop + # and respect the shutdown behavior of the async transport + if testcase["env_http_proxy"] is not None: + monkeypatch.setenv("HTTP_PROXY", testcase["env_http_proxy"]) + if testcase["env_https_proxy"] is not None: + monkeypatch.setenv("HTTPS_PROXY", testcase["env_https_proxy"]) + if testcase.get("env_no_proxy") is not None: + monkeypatch.setenv("NO_PROXY", testcase["env_no_proxy"]) + + kwargs = { + "_experiments": {"transport_async": True}, + "integrations": [AsyncioIntegration()], + } + + if testcase["arg_http_proxy"] is not None: + kwargs["http_proxy"] = testcase["arg_http_proxy"] + if testcase["arg_https_proxy"] is not None: + kwargs["https_proxy"] = testcase["arg_https_proxy"] + if testcase.get("arg_proxy_headers") is not None: + kwargs["proxy_headers"] = testcase["arg_proxy_headers"] + + client = Client(testcase["dsn"], **kwargs) + assert isinstance(client.transport, AsyncHttpTransport) + + proxy = getattr( + client.transport._pool, + "proxy", + getattr(client.transport._pool, "_proxy_url", None), + ) + if testcase["expected_proxy_scheme"] is None: + assert proxy is None + else: + scheme = ( + proxy.scheme.decode("ascii") + if isinstance(proxy.scheme, bytes) + else proxy.scheme + ) + assert scheme == testcase["expected_proxy_scheme"] + + if testcase.get("arg_proxy_headers") is not None: + proxy_headers = dict( + (k.decode("ascii"), v.decode("ascii")) + for k, v in client.transport._pool._proxy_headers + ) + assert proxy_headers == testcase["arg_proxy_headers"] + + await client.close_async() + + +@skip_under_gevent +@pytest.mark.asyncio +@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}, + integrations=[AsyncioIntegration()], + ) + assert isinstance(client.transport, AsyncHttpTransport) + + with _warnings.catch_warnings(record=True) as w: + _warnings.simplefilter("always") + client.close() + assert any("close_async()" in str(warning.message) for warning in w) + + +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async client methods require Python 3.8+") +async def test_close_async_with_async_transport(): + """Test close_async() properly closes async transport.""" + client = Client( + "https://foo@sentry.io/123", + _experiments={"transport_async": True}, + integrations=[AsyncioIntegration()], + ) + assert isinstance(client.transport, AsyncHttpTransport) + + await client.close_async(timeout=1.0) + assert client.transport is None + + +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async client methods require Python 3.8+") +async def test_close_async_with_sync_transport(): + """Test close_async() aborts with non-async transport.""" + client = Client("https://foo@sentry.io/123") + assert not isinstance(client.transport, AsyncHttpTransport) + + with mock.patch("sentry_sdk.client.logger") as mock_logger: + await client.close_async() + mock_logger.debug.assert_any_call( + "close_async() used with non-async transport, aborting. Please use close() instead." + ) + # Transport should NOT have been set to None + assert client.transport is not None + client.close() + + +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async client methods require Python 3.8+") +async def test_close_async_no_transport(): + """Test close_async() does nothing when transport is None.""" + client = Client("https://foo@sentry.io/123") + client.transport = None + # Should not raise + await client.close_async() + + +@skip_under_gevent +@pytest.mark.asyncio +@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}, + integrations=[AsyncioIntegration()], + ) + assert isinstance(client.transport, AsyncHttpTransport) + + with _warnings.catch_warnings(record=True) as w: + _warnings.simplefilter("always") + client.flush(timeout=1.0) + assert any("flush_async()" in str(warning.message) for warning in w) + await client.close_async() + + +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async client methods require Python 3.8+") +async def test_flush_async_with_async_transport(): + """Test flush_async() works with async transport.""" + client = Client( + "https://foo@sentry.io/123", + _experiments={"transport_async": True}, + integrations=[AsyncioIntegration()], + ) + assert isinstance(client.transport, AsyncHttpTransport) + + # Should not raise + await client.flush_async(timeout=1.0) + await client.close_async() + + +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async client methods require Python 3.8+") +async def test_flush_async_uses_shutdown_timeout_default(): + """Test flush_async() uses shutdown_timeout when no timeout provided.""" + client = Client( + "https://foo@sentry.io/123", + _experiments={"transport_async": True}, + integrations=[AsyncioIntegration()], + shutdown_timeout=5.0, + ) + assert isinstance(client.transport, AsyncHttpTransport) + + with mock.patch.object(client.transport, "flush", return_value=None) as mock_flush: + await client.flush_async() + mock_flush.assert_called_once_with(timeout=5.0, callback=None) + await client.close_async() + + +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async client methods require Python 3.8+") +async def test_flush_async_with_sync_transport(): + """Test flush_async() aborts with non-async transport.""" + client = Client("https://foo@sentry.io/123") + assert not isinstance(client.transport, AsyncHttpTransport) + + with mock.patch("sentry_sdk.client.logger") as mock_logger: + await client.flush_async() + mock_logger.debug.assert_any_call( + "flush_async() used with non-async transport, aborting. Please use flush() instead." + ) + client.close() + + +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async client methods require Python 3.8+") +async def test_flush_async_no_transport(): + """Test flush_async() does nothing when transport is None.""" + client = Client("https://foo@sentry.io/123") + client.transport = None + # Should not raise + await client.flush_async() + + +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async client methods require Python 3.8+") +async def test_client_async_context_manager(): + """Test Client works as async context manager.""" + async with Client( + "https://foo@sentry.io/123", + _experiments={"transport_async": True}, + integrations=[AsyncioIntegration()], + ) as client: + assert isinstance(client.transport, AsyncHttpTransport) + assert client.is_active() + # After __aexit__, transport should be None + assert client.transport is None + + +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async client methods require Python 3.8+") +async def test_client_async_context_manager_with_sync_transport(): + """Test Client async context manager with sync transport is safe.""" + async with Client("https://foo@sentry.io/123") as client: + assert client.is_active() + # close_async with sync transport is a no-op for transport cleanup + # Transport won't be None because close_async aborts for non-async transport + assert client.transport is not None + client.close() + + +@pytest.mark.parametrize("testcase", SOCKS_PROXY_TESTCASES) +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async transport requires Python 3.8+") +async def test_async_socks_proxy(testcase): + # These are just the same tests as the sync ones, but they need to be run in an event loop + # and respect the shutdown behavior of the async transport + + kwargs = { + "_experiments": {"transport_async": True}, + "integrations": [AsyncioIntegration()], + } + + if testcase["arg_http_proxy"] is not None: + kwargs["http_proxy"] = testcase["arg_http_proxy"] + if testcase["arg_https_proxy"] is not None: + kwargs["https_proxy"] = testcase["arg_https_proxy"] + + client = Client(testcase["dsn"], **kwargs) + assert isinstance(client.transport, AsyncHttpTransport) + + assert ("socks" in str(type(client.transport._pool)).lower()) == testcase[ + "should_be_socks_proxy" + ], ( + f"Expected {kwargs} to result in SOCKS == {testcase['should_be_socks_proxy']}" + f"but got {str(type(client.transport._pool))}" + ) + + await client.close_async() diff --git a/tests/test_exceptiongroup.py b/tests/test_exceptiongroup.py index 4c7afc58eb..c0d057abf8 100644 --- a/tests/test_exceptiongroup.py +++ b/tests/test_exceptiongroup.py @@ -306,3 +306,171 @@ def test_simple_exception(): exception_values = event["exception"]["values"] assert exception_values == expected_exception_values + + +@minimum_python_311 +def test_exceptiongroup_starlette_collapse(): + """ + Simulates the Starlette collapse_excgroups() pattern where a single-exception + ExceptionGroup is caught and the inner exception is unwrapped and re-raised. + + See: https://github.com/Kludex/starlette/blob/0e88e92b592bfa11fd92e331869a8d49ba34b541/starlette/_utils.py#L79-L87 + + When using FastAPI with multiple BaseHTTPMiddleware instances, anyio wraps + exceptions in ExceptionGroups. Starlette's collapse_excgroups() then unwraps + single-exception groups and re-raises the inner exception. + + When re-raising the unwrapped exception, Python implicitly sets __context__ + on it pointing back to the ExceptionGroup (because the re-raise happens + inside the except block that caught the ExceptionGroup), creating a cycle: + + ExceptionGroup -> .exceptions[0] -> ValueError -> __context__ -> ExceptionGroup + + Without cycle detection in exceptions_from_error(), this causes infinite + recursion and a silent RecursionError that drops the event. + """ + exception_group = None + + try: + try: + raise RuntimeError("something") + except RuntimeError: + raise ExceptionGroup( + "nested", + [ + ValueError(654), + ], + ) + except ExceptionGroup as exc: + exception_group = exc + unwrapped = exc.exceptions[0] + try: + raise unwrapped + except Exception: + pass + + (event, _) = event_from_exception( + exception_group, + client_options={ + "include_local_variables": True, + "include_source_context": True, + "max_value_length": 1024, + }, + mechanism={"type": "test_suite", "handled": False}, + ) + + values = event["exception"]["values"] + + # For this test the stacktrace and the module is not important + for x in values: + if "stacktrace" in x: + del x["stacktrace"] + if "module" in x: + del x["module"] + + expected_values = [ + { + "mechanism": { + "exception_id": 2, + "handled": False, + "parent_id": 0, + "source": "exceptions[0]", + "type": "chained", + }, + "type": "ValueError", + "value": "654", + }, + { + "mechanism": { + "exception_id": 1, + "handled": False, + "parent_id": 0, + "source": "__context__", + "type": "chained", + }, + "type": "RuntimeError", + "value": "something", + }, + { + "mechanism": { + "exception_id": 0, + "handled": False, + "is_exception_group": True, + "type": "test_suite", + }, + "type": "ExceptionGroup", + "value": "nested", + }, + ] + + assert values == expected_values + + +@minimum_python_311 +def test_cyclic_exception_group_cause(): + """ + Test case related to `test_exceptiongroup_starlette_collapse` above. We want to make sure that + the same cyclic loop cannot happen via the __cause__ as well as the __context__ + """ + + original = ValueError("original error") + group = ExceptionGroup("unhandled errors in a TaskGroup", [original]) + original.__cause__ = group + original.__suppress_context__ = True + + # When the ExceptionGroup is the top-level exception, exceptions_from_error + # is called directly (not walk_exception_chain which has cycle detection). + (event, _) = event_from_exception( + group, + client_options={ + "include_local_variables": True, + "include_source_context": True, + "max_value_length": 1024, + }, + mechanism={"type": "test_suite", "handled": False}, + ) + + exception_values = event["exception"]["values"] + + # Must produce a finite list of exceptions without hitting RecursionError. + assert len(exception_values) >= 1 + exc_types = [v["type"] for v in exception_values] + assert "ExceptionGroup" in exc_types + assert "ValueError" in exc_types + + +@minimum_python_311 +def test_deeply_nested_cyclic_exception_group(): + """ + Related to the `test_exceptiongroup_starlette_collapse` test above. + + Testing a more complex cycle: ExceptionGroup -> ValueError -> __cause__ -> + ExceptionGroup (nested) -> TypeError -> __cause__ -> original ExceptionGroup + """ + inner_error = TypeError("inner") + outer_error = ValueError("outer") + inner_group = ExceptionGroup("inner group", [inner_error]) + outer_group = ExceptionGroup("outer group", [outer_error]) + + # Create a cycle spanning two ExceptionGroups + outer_error.__cause__ = inner_group + outer_error.__suppress_context__ = True + inner_error.__cause__ = outer_group + inner_error.__suppress_context__ = True + + (event, _) = event_from_exception( + outer_group, + client_options={ + "include_local_variables": True, + "include_source_context": True, + "max_value_length": 1024, + }, + mechanism={"type": "test_suite", "handled": False}, + ) + + exception_values = event["exception"]["values"] + assert len(exception_values) >= 1 + exc_types = [v["type"] for v in exception_values] + assert "ExceptionGroup" in exc_types + assert "ValueError" in exc_types + assert "TypeError" in exc_types diff --git a/tests/test_scope.py b/tests/test_scope.py index 710ce33849..44510adaa8 100644 --- a/tests/test_scope.py +++ b/tests/test_scope.py @@ -876,7 +876,7 @@ def test_set_tags(): def test_last_event_id(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) assert Scope.last_event_id() is None @@ -886,7 +886,7 @@ def test_last_event_id(sentry_init): def test_last_event_id_transaction(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) assert Scope.last_event_id() is None @@ -897,7 +897,7 @@ def test_last_event_id_transaction(sentry_init): def test_last_event_id_cleared(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) # Make sure last_event_id is set sentry_sdk.capture_exception(Exception("test")) diff --git a/tests/test_transport.py b/tests/test_transport.py index 8601a4f138..a121d3f1be 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -3,6 +3,7 @@ import os import socket import sys +import asyncio from collections import defaultdict from datetime import datetime, timedelta, timezone from unittest import mock @@ -15,6 +16,17 @@ except (ImportError, ModuleNotFoundError): httpcore = None +try: + import gevent # noqa: F401 + + running_under_gevent = True +except ImportError: + running_under_gevent = False + +skip_under_gevent = pytest.mark.skipif( + running_under_gevent, reason="Async tests not compatible with gevent" +) + import sentry_sdk from sentry_sdk import ( Client, @@ -29,14 +41,37 @@ from sentry_sdk.transport import ( KEEP_ALIVE_SOCKET_OPTIONS, _parse_rate_limits, + AsyncHttpTransport, HttpTransport, ) from sentry_sdk.integrations.logging import LoggingIntegration, ignore_logger +from sentry_sdk.integrations.asyncio import AsyncioIntegration server = None +def _make_async_transport_options(**overrides): + defaults = { + "dsn": "https://foo@sentry.io/123", + "transport": None, + "_experiments": {"transport_async": True}, + "integrations": [AsyncioIntegration()], + "send_client_reports": True, + "transport_queue_size": 100, + "keep_alive": False, + "socket_options": None, + "ca_certs": None, + "cert_file": None, + "key_file": None, + "http_proxy": None, + "https_proxy": None, + "proxy_headers": None, + } + defaults.update(overrides) + return defaults + + @pytest.fixture(scope="module", autouse=True) def make_capturing_server(request): global server @@ -841,3 +876,168 @@ def test_record_lost_event_transaction_item(capturing_server, make_client, span_ "reason": "test", "quantity": span_count + 1, } in discarded_events + + +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.parametrize("debug", (True, False)) +@pytest.mark.parametrize("client_flush_method", ["close", "flush"]) +@pytest.mark.parametrize("use_pickle", (True, False)) +@pytest.mark.parametrize("compression_level", (0, 9, None)) +@pytest.mark.parametrize("compression_algo", ("gzip", "br", "", None)) +@pytest.mark.skipif(not PY38, reason="Async transport only supported in Python 3.8+") +async def test_transport_works_async( + capturing_server, + request, + capsys, + caplog, + debug, + make_client, + client_flush_method, + use_pickle, + compression_level, + compression_algo, +): + caplog.set_level(logging.DEBUG) + + experiments = {} + if compression_level is not None: + experiments["transport_compression_level"] = compression_level + + if compression_algo is not None: + experiments["transport_compression_algo"] = compression_algo + + # Enable async transport + experiments["transport_async"] = True + + client = make_client( + debug=debug, + _experiments=experiments, + integrations=[AsyncioIntegration()], + ) + + if use_pickle: + client = pickle.loads(pickle.dumps(client)) + + # Verify we're using async transport + assert isinstance(client.transport, AsyncHttpTransport), ( + "Expected AsyncHttpTransport" + ) + + sentry_sdk.get_global_scope().set_client(client) + request.addfinalizer(lambda: sentry_sdk.get_global_scope().set_client(None)) + + add_breadcrumb( + level="info", message="i like bread", timestamp=datetime.now(timezone.utc) + ) + capture_message("lΓΆl") + + if client_flush_method == "close": + await client.close_async(timeout=2.0) + if client_flush_method == "flush": + await client.flush_async(timeout=2.0) + + out, err = capsys.readouterr() + assert not err and not out + assert capturing_server.captured + should_compress = ( + # default is to compress with brotli if available, gzip otherwise + (compression_level is None) + or ( + # setting compression level to 0 means don't compress + compression_level > 0 + ) + ) and ( + # if we couldn't resolve to a known algo, we don't compress + compression_algo != "" + ) + + assert capturing_server.captured[0].compressed == should_compress + # After flush, the worker task is still running, but the end of the test will shut down the event loop + # Therefore, we need to explicitly close the client to clean up the worker task + assert any("Sending envelope" in record.msg for record in caplog.records) == debug + if client_flush_method == "flush": + await client.close_async(timeout=2.0) + + +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async transport requires Python 3.8+") +async def test_async_two_way_ssl_authentication(): + current_dir = os.path.dirname(__file__) + cert_file = f"{current_dir}/test.pem" + key_file = f"{current_dir}/test.key" + + client = Client( + "https://foo@sentry.io/123", + cert_file=cert_file, + key_file=key_file, + _experiments={"transport_async": True}, + integrations=[AsyncioIntegration()], + ) + assert isinstance(client.transport, AsyncHttpTransport) + + options = client.transport._get_pool_options() + assert options["ssl_context"] is not None + + await client.close_async() + + +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async transport requires Python 3.8+") +async def test_async_transport_concurrent_requests( + capturing_server, make_client, caplog +): + """Test multiple simultaneous envelope submissions""" + caplog.set_level(logging.DEBUG) + client = make_client( + _experiments={"transport_async": True}, integrations=[AsyncioIntegration()] + ) + assert isinstance(client.transport, AsyncHttpTransport) + sentry_sdk.get_global_scope().set_client(client) + + num_messages = 15 + + async def send_message(i): + capture_message(f"concurrent message {i}") + + tasks = [send_message(i) for i in range(num_messages)] + await asyncio.gather(*tasks) + await client.close_async(timeout=2.0) + assert len(capturing_server.captured) == num_messages + + +@skip_under_gevent +@pytest.mark.asyncio +@pytest.mark.skipif(not PY38, reason="Async transport requires Python 3.8+") +async def test_async_transport_rate_limiting_with_concurrency( + capturing_server, make_client, request +): + """Test async transport rate limiting with concurrent requests""" + client = make_client( + _experiments={"transport_async": True}, integrations=[AsyncioIntegration()] + ) + + assert isinstance(client.transport, AsyncHttpTransport) + sentry_sdk.get_global_scope().set_client(client) + request.addfinalizer(lambda: sentry_sdk.get_global_scope().set_client(None)) + capturing_server.respond_with( + code=429, headers={"X-Sentry-Rate-Limits": "60:error:organization"} + ) + + # Send one request first to trigger rate limiting + capture_message("initial message") + await asyncio.sleep(0.1) # Wait for request to execute + assert client.transport._check_disabled("error") is True + capturing_server.clear_captured() + + async def send_message(i): + capture_message(f"message {i}") + await asyncio.sleep(0.01) + + await asyncio.gather(*[send_message(i) for i in range(5)]) + await asyncio.sleep(0.1) + # New request should be dropped due to rate limiting + assert len(capturing_server.captured) == 0 + await client.close_async(timeout=2.0) diff --git a/tests/test_utils.py b/tests/test_utils.py index 1fc651f805..0fa116a57e 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -7,7 +7,6 @@ import pytest import sentry_sdk -from sentry_sdk._compat import PY38 from sentry_sdk.integrations import Integration from sentry_sdk._queue import Queue from sentry_sdk.utils import ( @@ -942,14 +941,12 @@ def target(): assert (main_thread.ident, main_thread.name) == results.get(timeout=1) -@pytest.mark.skipif(PY38, reason="Flakes a lot on 3.8 in CI.") def test_get_current_thread_meta_failed_to_get_main_thread(): results = Queue(maxsize=1) def target(): - with mock.patch("threading.current_thread", side_effect=["fake thread"]): - with mock.patch("threading.current_thread", side_effect=["fake thread"]): - results.put(get_current_thread_meta()) + with mock.patch("threading.current_thread", return_value="fake thread"): + results.put(get_current_thread_meta()) main_thread = threading.main_thread() diff --git a/tests/tracing/test_misc.py b/tests/tracing/test_misc.py index 8895c98dbc..c6fd6df84e 100644 --- a/tests/tracing/test_misc.py +++ b/tests/tracing/test_misc.py @@ -478,7 +478,7 @@ def test_start_transaction_updates_scope_name_source(sentry_init): @pytest.mark.parametrize("sampled", (True, None)) def test_transaction_dropped_debug_not_started(sentry_init, sampled): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) tx = Transaction(sampled=sampled) @@ -498,7 +498,7 @@ def test_transaction_dropped_debug_not_started(sentry_init, sampled): def test_transaction_dropeed_sampled_false(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) tx = Transaction(sampled=False) @@ -516,7 +516,7 @@ def test_transaction_dropeed_sampled_false(sentry_init): def test_transaction_not_started_warning(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) tx = Transaction() diff --git a/tests/tracing/test_propagation.py b/tests/tracing/test_propagation.py index 730bf2672b..77993d9c33 100644 --- a/tests/tracing/test_propagation.py +++ b/tests/tracing/test_propagation.py @@ -3,7 +3,7 @@ def test_standalone_span_iter_headers(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) with sentry_sdk.start_span(op="test") as span: with pytest.raises(StopIteration): @@ -12,7 +12,7 @@ def test_standalone_span_iter_headers(sentry_init): def test_span_in_span_iter_headers(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) with sentry_sdk.start_span(op="test"): with sentry_sdk.start_span(op="test2") as span_inner: @@ -22,7 +22,7 @@ def test_span_in_span_iter_headers(sentry_init): def test_span_in_transaction(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) with sentry_sdk.start_transaction(op="test"): with sentry_sdk.start_span(op="test2") as span: @@ -31,7 +31,7 @@ def test_span_in_transaction(sentry_init): def test_span_in_span_in_transaction(sentry_init): - sentry_init(enable_tracing=True) + sentry_init(traces_sample_rate=1.0) with sentry_sdk.start_transaction(op="test"): with sentry_sdk.start_span(op="test2"): diff --git a/tests/tracing/test_span_streaming.py b/tests/tracing/test_span_streaming.py index 21c3d26ea3..44f504cc26 100644 --- a/tests/tracing/test_span_streaming.py +++ b/tests/tracing/test_span_streaming.py @@ -2,8 +2,8 @@ import re import sys import time -from typing import Any from unittest import mock +from typing import Any import pytest @@ -11,6 +11,7 @@ from sentry_sdk.profiler.continuous_profiler import get_profiler_id from sentry_sdk.traces import NoOpStreamedSpan, SpanStatus, StreamedSpan + minimum_python_38 = pytest.mark.skipif( sys.version_info < (3, 8), reason="Asyncio tests need Python >= 3.8" ) @@ -1539,7 +1540,6 @@ def test_transport_format(sentry_init, capture_envelopes): "start_timestamp": mock.ANY, "end_timestamp": mock.ANY, "attributes": { - "sentry.span.source": {"value": "custom", "type": "string"}, "thread.id": {"value": mock.ANY, "type": "string"}, "thread.name": {"value": "MainThread", "type": "string"}, "sentry.segment.id": {"value": mock.ANY, "type": "string"}, diff --git a/tox.ini b/tox.ini index 1772ee1c73..9a974973a2 100644 --- a/tox.ini +++ b/tox.ini @@ -59,14 +59,14 @@ envlist = {py3.10,py3.12,py3.13}-mcp-v1.15.0 {py3.10,py3.12,py3.13}-mcp-v1.19.0 {py3.10,py3.12,py3.13}-mcp-v1.23.3 - {py3.10,py3.12,py3.13}-mcp-v1.26.0 + {py3.10,py3.12,py3.13}-mcp-v1.27.0 {py3.10,py3.12,py3.13}-mcp-latest {py3.10,py3.13,py3.14,py3.14t}-fastmcp-v0.1.0 {py3.10,py3.13,py3.14,py3.14t}-fastmcp-v0.4.1 {py3.10,py3.13,py3.14,py3.14t}-fastmcp-v1.0 - {py3.10,py3.12,py3.13}-fastmcp-v2.14.5 - {py3.10,py3.12,py3.13}-fastmcp-v3.1.1 + {py3.10,py3.12,py3.13}-fastmcp-v2.14.7 + {py3.10,py3.12,py3.13}-fastmcp-v3.2.3 {py3.10,py3.12,py3.13}-fastmcp-latest @@ -74,70 +74,70 @@ envlist = {py3.10,py3.11,py3.12}-openai_agents-v0.0.19 {py3.10,py3.12,py3.13}-openai_agents-v0.4.2 {py3.10,py3.13,py3.14,py3.14t}-openai_agents-v0.8.4 - {py3.10,py3.13,py3.14,py3.14t}-openai_agents-v0.12.5 + {py3.10,py3.13,py3.14,py3.14t}-openai_agents-v0.13.6 {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.12,py3.13}-pydantic_ai-v1.23.0 - {py3.10,py3.12,py3.13}-pydantic_ai-v1.47.0 - {py3.10,py3.13,py3.14}-pydantic_ai-v1.70.0 + {py3.10,py3.12,py3.13}-pydantic_ai-v1.26.0 + {py3.10,py3.12,py3.13}-pydantic_ai-v1.53.0 + {py3.10,py3.13,py3.14}-pydantic_ai-v1.80.0 {py3.10,py3.13,py3.14}-pydantic_ai-latest # ~~~ AI Workflow ~~~ {py3.9,py3.11,py3.12}-langchain-base-v0.1.20 {py3.9,py3.12,py3.13}-langchain-base-v0.3.28 - {py3.10,py3.13,py3.14}-langchain-base-v1.2.12 + {py3.10,py3.13,py3.14}-langchain-base-v1.2.15 {py3.10,py3.13,py3.14}-langchain-base-latest {py3.9,py3.11,py3.12}-langchain-notiktoken-v0.1.20 {py3.9,py3.12,py3.13}-langchain-notiktoken-v0.3.28 - {py3.10,py3.13,py3.14}-langchain-notiktoken-v1.2.12 + {py3.10,py3.13,py3.14}-langchain-notiktoken-v1.2.15 {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.1.3 + {py3.10,py3.12,py3.13}-langgraph-v1.1.6 + {py3.10,py3.12,py3.13}-langgraph-v1.1.7a1 {py3.10,py3.12,py3.13}-langgraph-latest # ~~~ AI ~~~ {py3.8,py3.11,py3.12}-anthropic-v0.16.0 - {py3.8,py3.11,py3.12}-anthropic-v0.39.0 - {py3.8,py3.12,py3.13}-anthropic-v0.62.0 - {py3.9,py3.13,py3.14,py3.14t}-anthropic-v0.86.0 + {py3.8,py3.11,py3.12}-anthropic-v0.42.0 + {py3.8,py3.12,py3.13}-anthropic-v0.68.2 + {py3.9,py3.13,py3.14,py3.14t}-anthropic-v0.94.0 {py3.9,py3.13,py3.14,py3.14t}-anthropic-latest {py3.9,py3.10,py3.11}-cohere-v5.4.0 - {py3.9,py3.11,py3.12}-cohere-v5.10.0 - {py3.9,py3.11,py3.12}-cohere-v5.15.0 - {py3.9,py3.13,py3.14}-cohere-v5.20.7 - {py3.9,py3.13,py3.14}-cohere-latest + {py3.9,py3.13,py3.14}-cohere-v5.21.1 + {py3.10,py3.13,py3.14}-cohere-v6.1.0 + {py3.10,py3.13,py3.14}-cohere-latest {py3.9,py3.12,py3.13}-google_genai-v1.29.0 - {py3.9,py3.12,py3.13}-google_genai-v1.42.0 - {py3.10,py3.13,py3.14,py3.14t}-google_genai-v1.55.0 - {py3.10,py3.13,py3.14,py3.14t}-google_genai-v1.68.0 + {py3.9,py3.12,py3.13}-google_genai-v1.43.0 + {py3.10,py3.13,py3.14,py3.14t}-google_genai-v1.57.0 + {py3.10,py3.13,py3.14,py3.14t}-google_genai-v1.72.0 {py3.10,py3.13,py3.14,py3.14t}-google_genai-latest {py3.8,py3.10,py3.11}-huggingface_hub-v0.24.7 {py3.8,py3.12,py3.13}-huggingface_hub-v0.36.2 - {py3.9,py3.13,py3.14,py3.14t}-huggingface_hub-v1.7.1 - {py3.9,py3.13,py3.14,py3.14t}-huggingface_hub-latest + {py3.10,py3.13,py3.14,py3.14t}-huggingface_hub-v1.10.1 + {py3.10,py3.13,py3.14,py3.14t}-huggingface_hub-latest {py3.9,py3.12,py3.13}-litellm-v1.77.7 {py3.9,py3.12,py3.13}-litellm-v1.79.3 {py3.9,py3.12,py3.13}-litellm-v1.81.16 - {py3.9,py3.12,py3.13}-litellm-v1.82.4 - {py3.9,py3.12,py3.13}-litellm-latest + {py3.9,py3.13,py3.14}-litellm-v1.83.4 + {py3.9,py3.13,py3.14}-litellm-latest {py3.8,py3.11,py3.12}-openai-base-v1.0.1 {py3.8,py3.12,py3.13}-openai-base-v1.109.1 - {py3.9,py3.13,py3.14,py3.14t}-openai-base-v2.29.0 + {py3.9,py3.13,py3.14,py3.14t}-openai-base-v2.31.0 {py3.9,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.9,py3.13,py3.14,py3.14t}-openai-notiktoken-v2.29.0 + {py3.9,py3.13,py3.14,py3.14t}-openai-notiktoken-v2.31.0 {py3.9,py3.13,py3.14,py3.14t}-openai-notiktoken-latest @@ -145,7 +145,7 @@ envlist = {py3.6,py3.7}-boto3-v1.12.49 {py3.6,py3.9,py3.10}-boto3-v1.21.46 {py3.7,py3.11,py3.12}-boto3-v1.33.13 - {py3.9,py3.13,py3.14,py3.14t}-boto3-v1.42.71 + {py3.9,py3.13,py3.14,py3.14t}-boto3-v1.42.88 {py3.9,py3.13,py3.14,py3.14t}-boto3-latest {py3.6,py3.7,py3.8}-chalice-v1.16.0 @@ -173,7 +173,8 @@ envlist = {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 - {py3.10,py3.13,py3.14,py3.14t}-redis-v7.3.0 + {py3.10,py3.13,py3.14,py3.14t}-redis-v7.4.0 + {py3.10,py3.13,py3.14,py3.14t}-redis-v8.0.0b1 {py3.10,py3.13,py3.14,py3.14t}-redis-latest {py3.6}-redis_py_cluster_legacy-v1.3.6 @@ -182,7 +183,7 @@ envlist = {py3.6,py3.8,py3.9}-sqlalchemy-v1.2.19 {py3.6,py3.11,py3.12}-sqlalchemy-v1.4.54 - {py3.7,py3.12,py3.13}-sqlalchemy-v2.0.48 + {py3.7,py3.12,py3.13}-sqlalchemy-v2.0.49 {py3.10,py3.13,py3.14,py3.14t}-sqlalchemy-v2.1.0b1 {py3.7,py3.12,py3.13}-sqlalchemy-latest @@ -207,12 +208,13 @@ envlist = # ~~~ GraphQL ~~~ {py3.8,py3.10,py3.11}-ariadne-v0.20.1 - {py3.10,py3.13,py3.14,py3.14t}-ariadne-v1.0.0 + {py3.10,py3.13,py3.14,py3.14t}-ariadne-v1.0.1 + {py3.10,py3.13,py3.14,py3.14t}-ariadne-v1.1.0a2 {py3.10,py3.13,py3.14,py3.14t}-ariadne-latest {py3.6,py3.9,py3.10}-gql-v3.4.1 {py3.9,py3.12,py3.13}-gql-v4.0.0 - {py3.9,py3.13,py3.14,py3.14t}-gql-v4.3.0b0 + {py3.9,py3.13,py3.14,py3.14t}-gql-v4.3.0b2 {py3.9,py3.12,py3.13}-gql-latest {py3.6,py3.9,py3.10}-graphene-v3.3 @@ -220,16 +222,15 @@ envlist = {py3.8,py3.12,py3.13}-graphene-latest {py3.8,py3.10,py3.11}-strawberry-v0.209.8 - {py3.10,py3.13,py3.14,py3.14t}-strawberry-v0.311.3 + {py3.10,py3.13,py3.14,py3.14t}-strawberry-v0.314.3 {py3.10,py3.13,py3.14,py3.14t}-strawberry-latest # ~~~ Network ~~~ {py3.7,py3.8}-grpc-v1.32.0 - {py3.7,py3.9,py3.10}-grpc-v1.47.5 - {py3.7,py3.11,py3.12}-grpc-v1.62.3 - {py3.9,py3.13,py3.14}-grpc-v1.78.0 - {py3.9,py3.13,py3.14}-grpc-v1.80.0rc1 + {py3.7,py3.9,py3.10}-grpc-v1.48.2 + {py3.8,py3.11,py3.12}-grpc-v1.64.3 + {py3.9,py3.13,py3.14}-grpc-v1.80.0 {py3.9,py3.13,py3.14}-grpc-latest {py3.6,py3.8,py3.9}-httpx-v0.16.1 @@ -238,9 +239,12 @@ envlist = {py3.9,py3.11,py3.12}-httpx-v0.28.1 {py3.9,py3.11,py3.12}-httpx-latest + {py3.11,py3.13,py3.14}-pyreqwest-v0.11.6 + {py3.11,py3.13,py3.14}-pyreqwest-latest + {py3.6}-requests-v2.12.5 - {py3.9,py3.13,py3.14,py3.14t}-requests-v2.32.5 - {py3.9,py3.13,py3.14,py3.14t}-requests-latest + {py3.10,py3.13,py3.14,py3.14t}-requests-v2.33.1 + {py3.10,py3.13,py3.14,py3.14t}-requests-latest # ~~~ Tasks ~~~ @@ -249,12 +253,11 @@ envlist = {py3.9,py3.12,py3.13}-arq-latest {py3.7}-beam-v2.14.0 - {py3.10,py3.12,py3.13}-beam-v2.71.0 - {py3.10,py3.12,py3.13}-beam-v2.72.0rc2 + {py3.10,py3.12,py3.13}-beam-v2.72.0 {py3.10,py3.12,py3.13}-beam-latest {py3.6,py3.7,py3.8}-celery-v4.4.7 - {py3.9,py3.12,py3.13}-celery-v5.6.2 + {py3.9,py3.12,py3.13}-celery-v5.6.3 {py3.9,py3.12,py3.13}-celery-latest {py3.6,py3.7}-dramatiq-v1.9.0 @@ -266,7 +269,7 @@ envlist = {py3.6,py3.13,py3.14,py3.14t}-huey-latest {py3.9,py3.10}-ray-v2.7.2 - {py3.10,py3.12,py3.13}-ray-v2.54.0 + {py3.10,py3.12,py3.13}-ray-v2.54.1 {py3.10,py3.12,py3.13}-ray-latest {py3.6}-rq-v0.6.0 @@ -285,9 +288,9 @@ envlist = {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.8,py3.11,py3.12}-django-v4.2.29 - {py3.10,py3.13,py3.14,py3.14t}-django-v5.2.12 - {py3.12,py3.13,py3.14,py3.14t}-django-v6.0.3 + {py3.8,py3.11,py3.12}-django-v4.2.30 + {py3.10,py3.13,py3.14,py3.14t}-django-v5.2.13 + {py3.12,py3.13,py3.14,py3.14t}-django-v6.0.4 {py3.12,py3.13,py3.14,py3.14t}-django-latest {py3.6,py3.7,py3.8}-flask-v1.1.4 @@ -296,16 +299,14 @@ envlist = {py3.9,py3.13,py3.14,py3.14t}-flask-latest {py3.6,py3.9,py3.10}-starlette-v0.16.0 - {py3.7,py3.10,py3.11}-starlette-v0.28.0 - {py3.8,py3.12,py3.13}-starlette-v0.40.0 {py3.10,py3.13,py3.14,py3.14t}-starlette-v0.52.1 - {py3.10,py3.13,py3.14,py3.14t}-starlette-v1.0.0rc1 + {py3.10,py3.13,py3.14,py3.14t}-starlette-v1.0.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.98.0 {py3.8,py3.12,py3.13}-fastapi-v0.117.1 - {py3.10,py3.13,py3.14,py3.14t}-fastapi-v0.135.1 + {py3.10,py3.13,py3.14,py3.14t}-fastapi-v0.135.3 {py3.10,py3.13,py3.14,py3.14t}-fastapi-latest @@ -313,7 +314,7 @@ envlist = {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.9,py3.13,py3.14,py3.14t}-aiohttp-v3.13.3 + {py3.9,py3.13,py3.14,py3.14t}-aiohttp-v3.13.5 {py3.9,py3.13,py3.14,py3.14t}-aiohttp-latest {py3.6,py3.7}-bottle-v0.12.25 @@ -386,14 +387,17 @@ deps = linters: -r requirements-linting.txt linters: werkzeug<2.3.0 + linters: httpcore[asyncio] mypy: -r requirements-linting.txt mypy: werkzeug<2.3.0 + mypy: httpcore[asyncio] ruff: -r requirements-linting.txt # === Common === py3.8-common: hypothesis common: pytest-asyncio + common: httpcore[asyncio] # 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 @@ -448,16 +452,16 @@ deps = mcp-v1.15.0: mcp==1.15.0 mcp-v1.19.0: mcp==1.19.0 mcp-v1.23.3: mcp==1.23.3 - mcp-v1.26.0: mcp==1.26.0 - mcp-latest: mcp==1.26.0 + mcp-v1.27.0: mcp==1.27.0 + mcp-latest: mcp==1.27.0 mcp: pytest-asyncio fastmcp-v0.1.0: fastmcp==0.1.0 fastmcp-v0.4.1: fastmcp==0.4.1 fastmcp-v1.0: fastmcp==1.0 - fastmcp-v2.14.5: fastmcp==2.14.5 - fastmcp-v3.1.1: fastmcp==3.1.1 - fastmcp-latest: fastmcp==3.1.1 + fastmcp-v2.14.7: fastmcp==2.14.7 + fastmcp-v3.2.3: fastmcp==3.2.3 + fastmcp-latest: fastmcp==3.2.3 fastmcp: pytest-asyncio @@ -465,99 +469,103 @@ deps = openai_agents-v0.0.19: openai-agents==0.0.19 openai_agents-v0.4.2: openai-agents==0.4.2 openai_agents-v0.8.4: openai-agents==0.8.4 - openai_agents-v0.12.5: openai-agents==0.12.5 - openai_agents-latest: openai-agents==0.12.5 + openai_agents-v0.13.6: openai-agents==0.13.6 + openai_agents-latest: openai-agents==0.13.6 openai_agents: pytest-asyncio pydantic_ai-v1.0.18: pydantic-ai==1.0.18 - pydantic_ai-v1.23.0: pydantic-ai==1.23.0 - pydantic_ai-v1.47.0: pydantic-ai==1.47.0 - pydantic_ai-v1.70.0: pydantic-ai==1.70.0 - pydantic_ai-latest: pydantic-ai==1.70.0 + pydantic_ai-v1.26.0: pydantic-ai==1.26.0 + pydantic_ai-v1.53.0: pydantic-ai==1.53.0 + pydantic_ai-v1.80.0: pydantic-ai==1.80.0 + pydantic_ai-latest: pydantic-ai==1.80.0 pydantic_ai: pytest-asyncio # ~~~ AI Workflow ~~~ langchain-base-v0.1.20: langchain==0.1.20 langchain-base-v0.3.28: langchain==0.3.28 - langchain-base-v1.2.12: langchain==1.2.12 - langchain-base-latest: langchain==1.2.12 + langchain-base-v1.2.15: langchain==1.2.15 + langchain-base-latest: langchain==1.2.15 langchain-base: pytest-asyncio langchain-base: openai langchain-base: tiktoken langchain-base: langchain-openai langchain-base-v0.3.28: langchain-community - langchain-base-v1.2.12: langchain-community - langchain-base-v1.2.12: langchain-classic + langchain-base-v1.2.15: langchain-community + langchain-base-v1.2.15: langchain-classic langchain-base-latest: langchain-community langchain-base-latest: langchain-classic langchain-notiktoken-v0.1.20: langchain==0.1.20 langchain-notiktoken-v0.3.28: langchain==0.3.28 - langchain-notiktoken-v1.2.12: langchain==1.2.12 - langchain-notiktoken-latest: langchain==1.2.12 + langchain-notiktoken-v1.2.15: langchain==1.2.15 + langchain-notiktoken-latest: langchain==1.2.15 langchain-notiktoken: pytest-asyncio langchain-notiktoken: openai langchain-notiktoken: langchain-openai langchain-notiktoken-v0.3.28: langchain-community - langchain-notiktoken-v1.2.12: langchain-community - langchain-notiktoken-v1.2.12: langchain-classic + langchain-notiktoken-v1.2.15: langchain-community + langchain-notiktoken-v1.2.15: langchain-classic langchain-notiktoken-latest: langchain-community langchain-notiktoken-latest: langchain-classic langgraph-v0.6.11: langgraph==0.6.11 - langgraph-v1.1.3: langgraph==1.1.3 - langgraph-latest: langgraph==1.1.3 + langgraph-v1.1.6: langgraph==1.1.6 + langgraph-v1.1.7a1: langgraph==1.1.7a1 + langgraph-latest: langgraph==1.1.6 # ~~~ AI ~~~ anthropic-v0.16.0: anthropic==0.16.0 - anthropic-v0.39.0: anthropic==0.39.0 - anthropic-v0.62.0: anthropic==0.62.0 - anthropic-v0.86.0: anthropic==0.86.0 - anthropic-latest: anthropic==0.86.0 + anthropic-v0.42.0: anthropic==0.42.0 + anthropic-v0.68.2: anthropic==0.68.2 + anthropic-v0.94.0: anthropic==0.94.0 + anthropic-latest: anthropic==0.94.0 anthropic: pytest-asyncio anthropic-v0.16.0: httpx<0.28.0 - anthropic-v0.39.0: httpx<0.28.0 + anthropic-v0.42.0: httpx<0.28.0 + {py3.8}-anthropic: tokenizers<0.20.4 cohere-v5.4.0: cohere==5.4.0 - cohere-v5.10.0: cohere==5.10.0 - cohere-v5.15.0: cohere==5.15.0 - cohere-v5.20.7: cohere==5.20.7 - cohere-latest: cohere==5.20.7 + cohere-v5.21.1: cohere==5.21.1 + cohere-v6.1.0: cohere==6.1.0 + cohere-latest: cohere==6.1.0 google_genai-v1.29.0: google-genai==1.29.0 - google_genai-v1.42.0: google-genai==1.42.0 - google_genai-v1.55.0: google-genai==1.55.0 - google_genai-v1.68.0: google-genai==1.68.0 - google_genai-latest: google-genai==1.68.0 + google_genai-v1.43.0: google-genai==1.43.0 + google_genai-v1.57.0: google-genai==1.57.0 + google_genai-v1.72.0: google-genai==1.72.0 + google_genai-latest: google-genai==1.72.0 google_genai: pytest-asyncio huggingface_hub-v0.24.7: huggingface_hub==0.24.7 huggingface_hub-v0.36.2: huggingface_hub==0.36.2 - huggingface_hub-v1.7.1: huggingface_hub==1.7.1 - huggingface_hub-latest: huggingface_hub==1.7.1 + huggingface_hub-v1.10.1: huggingface_hub==1.10.1 + huggingface_hub-latest: huggingface_hub==1.10.1 huggingface_hub: responses huggingface_hub: pytest-httpx litellm-v1.77.7: litellm==1.77.7 litellm-v1.79.3: litellm==1.79.3 litellm-v1.81.16: litellm==1.81.16 - litellm-v1.82.4: litellm==1.82.4 - litellm-latest: litellm==1.82.4 + litellm-v1.83.4: litellm==1.83.4 + litellm-latest: litellm==1.83.4 + litellm: anthropic + litellm: google-genai + litellm: pytest-asyncio openai-base-v1.0.1: openai==1.0.1 openai-base-v1.109.1: openai==1.109.1 - openai-base-v2.29.0: openai==2.29.0 - openai-base-latest: openai==2.29.0 + openai-base-v2.31.0: openai==2.31.0 + openai-base-latest: openai==2.31.0 openai-base: pytest-asyncio openai-base: tiktoken openai-base-v1.0.1: httpx<0.28 openai-notiktoken-v1.0.1: openai==1.0.1 openai-notiktoken-v1.109.1: openai==1.109.1 - openai-notiktoken-v2.29.0: openai==2.29.0 - openai-notiktoken-latest: openai==2.29.0 + openai-notiktoken-v2.31.0: openai==2.31.0 + openai-notiktoken-latest: openai==2.31.0 openai-notiktoken: pytest-asyncio openai-notiktoken-v1.0.1: httpx<0.28 @@ -566,8 +574,8 @@ deps = boto3-v1.12.49: boto3==1.12.49 boto3-v1.21.46: boto3==1.21.46 boto3-v1.33.13: boto3==1.33.13 - boto3-v1.42.71: boto3==1.42.71 - boto3-latest: boto3==1.42.71 + boto3-v1.42.88: boto3==1.42.88 + boto3-latest: boto3==1.42.88 {py3.7,py3.8}-boto3: urllib3<2.0.0 chalice-v1.16.0: chalice==1.16.0 @@ -599,8 +607,9 @@ deps = redis-v4.6.0: redis==4.6.0 redis-v5.3.1: redis==5.3.1 redis-v6.4.0: redis==6.4.0 - redis-v7.3.0: redis==7.3.0 - redis-latest: redis==7.3.0 + redis-v7.4.0: redis==7.4.0 + redis-v8.0.0b1: redis==8.0.0b1 + redis-latest: redis==7.4.0 redis: fakeredis!=1.7.4 redis: pytest<8.0.0 redis-v4.6.0: fakeredis<2.31.0 @@ -613,9 +622,9 @@ deps = sqlalchemy-v1.2.19: sqlalchemy==1.2.19 sqlalchemy-v1.4.54: sqlalchemy==1.4.54 - sqlalchemy-v2.0.48: sqlalchemy==2.0.48 + sqlalchemy-v2.0.49: sqlalchemy==2.0.49 sqlalchemy-v2.1.0b1: sqlalchemy==2.1.0b1 - sqlalchemy-latest: sqlalchemy==2.0.48 + sqlalchemy-latest: sqlalchemy==2.0.49 # ~~~ Flags ~~~ @@ -639,15 +648,16 @@ deps = # ~~~ GraphQL ~~~ ariadne-v0.20.1: ariadne==0.20.1 - ariadne-v1.0.0: ariadne==1.0.0 - ariadne-latest: ariadne==1.0.0 + ariadne-v1.0.1: ariadne==1.0.1 + ariadne-v1.1.0a2: ariadne==1.1.0a2 + ariadne-latest: ariadne==1.0.1 ariadne: fastapi ariadne: flask ariadne: httpx gql-v3.4.1: gql[all]==3.4.1 gql-v4.0.0: gql[all]==4.0.0 - gql-v4.3.0b0: gql[all]==4.3.0b0 + gql-v4.3.0b2: gql[all]==4.3.0b2 gql-latest: gql[all]==4.0.0 graphene-v3.3: graphene==3.3 @@ -660,19 +670,18 @@ deps = {py3.6}-graphene: aiocontextvars strawberry-v0.209.8: strawberry-graphql[fastapi,flask]==0.209.8 - strawberry-v0.311.3: strawberry-graphql[fastapi,flask]==0.311.3 - strawberry-latest: strawberry-graphql[fastapi,flask]==0.311.3 + strawberry-v0.314.3: strawberry-graphql[fastapi,flask]==0.314.3 + strawberry-latest: strawberry-graphql[fastapi,flask]==0.314.3 strawberry: httpx strawberry-v0.209.8: pydantic<2.11 # ~~~ Network ~~~ grpc-v1.32.0: grpcio==1.32.0 - grpc-v1.47.5: grpcio==1.47.5 - grpc-v1.62.3: grpcio==1.62.3 - grpc-v1.78.0: grpcio==1.78.0 - grpc-v1.80.0rc1: grpcio==1.80.0rc1 - grpc-latest: grpcio==1.78.0 + grpc-v1.48.2: grpcio==1.48.2 + grpc-v1.64.3: grpcio==1.64.3 + grpc-v1.80.0: grpcio==1.80.0 + grpc-latest: grpcio==1.80.0 grpc: protobuf grpc: mypy-protobuf grpc: types-protobuf @@ -683,16 +692,22 @@ deps = httpx-v0.24.1: httpx==0.24.1 httpx-v0.28.1: httpx==0.28.1 httpx-latest: httpx==0.28.1 - httpx: anyio<4.0.0 + httpx: anyio>=3,<5 + httpx-v0.16.1: anyio<4 + httpx-v0.20.0: anyio<4 httpx-v0.16.1: pytest-httpx==0.10.0 httpx-v0.20.0: pytest-httpx==0.14.0 httpx-v0.24.1: pytest-httpx==0.22.0 httpx-v0.28.1: pytest-httpx==0.35.0 httpx-latest: pytest-httpx==0.35.0 + pyreqwest-v0.11.6: pyreqwest==0.11.6 + pyreqwest-latest: pyreqwest==0.11.6 + pyreqwest: pytest-asyncio + requests-v2.12.5: requests==2.12.5 - requests-v2.32.5: requests==2.32.5 - requests-latest: requests==2.32.5 + requests-v2.33.1: requests==2.33.1 + requests-latest: requests==2.33.1 # ~~~ Tasks ~~~ @@ -705,14 +720,13 @@ deps = arq-v0.23: pydantic<2 beam-v2.14.0: apache-beam==2.14.0 - beam-v2.71.0: apache-beam==2.71.0 - beam-v2.72.0rc2: apache-beam==2.72.0rc2 - beam-latest: apache-beam==2.71.0 + beam-v2.72.0: apache-beam==2.72.0 + beam-latest: apache-beam==2.72.0 beam: dill celery-v4.4.7: celery==4.4.7 - celery-v5.6.2: celery==5.6.2 - celery-latest: celery==5.6.2 + celery-v5.6.3: celery==5.6.3 + celery-latest: celery==5.6.3 celery: newrelic<10.17.0 celery: redis {py3.7}-celery: importlib-metadata<5.0 @@ -726,8 +740,8 @@ deps = huey-latest: huey==2.6.0 ray-v2.7.2: ray==2.7.2 - ray-v2.54.0: ray==2.54.0 - ray-latest: ray==2.54.0 + ray-v2.54.1: ray==2.54.1 + ray-latest: ray==2.54.1 rq-v0.6.0: rq==0.6.0 rq-v0.13.0: rq==0.13.0 @@ -750,24 +764,24 @@ deps = django-v1.11.29: django==1.11.29 django-v2.2.28: django==2.2.28 django-v3.2.25: django==3.2.25 - django-v4.2.29: django==4.2.29 - django-v5.2.12: django==5.2.12 - django-v6.0.3: django==6.0.3 - django-latest: django==6.0.3 + django-v4.2.30: django==4.2.30 + django-v5.2.13: django==5.2.13 + django-v6.0.4: django==6.0.4 + django-latest: django==6.0.4 django: psycopg2-binary django: djangorestframework django: pytest-django django: Werkzeug django-v2.2.28: channels[daphne] django-v3.2.25: channels[daphne] - django-v4.2.29: channels[daphne] - django-v5.2.12: channels[daphne] - django-v6.0.3: channels[daphne] + django-v4.2.30: channels[daphne] + django-v5.2.13: channels[daphne] + django-v6.0.4: channels[daphne] django-v2.2.28: six django-v3.2.25: pytest-asyncio - django-v4.2.29: pytest-asyncio - django-v5.2.12: pytest-asyncio - django-v6.0.3: pytest-asyncio + django-v4.2.30: pytest-asyncio + django-v5.2.13: pytest-asyncio + django-v6.0.4: pytest-asyncio django-v1.11.29: djangorestframework>=3.0,<4.0 django-v1.11.29: Werkzeug<2.1.0 django-v2.2.28: djangorestframework>=3.0,<4.0 @@ -790,11 +804,9 @@ deps = flask-v1.1.4: markupsafe<2.1.0 starlette-v0.16.0: starlette==0.16.0 - starlette-v0.28.0: starlette==0.28.0 - starlette-v0.40.0: starlette==0.40.0 starlette-v0.52.1: starlette==0.52.1 - starlette-v1.0.0rc1: starlette==1.0.0rc1 - starlette-latest: starlette==0.52.1 + starlette-v1.0.0: starlette==1.0.0 + starlette-latest: starlette==1.0.0 starlette: pytest-asyncio starlette: python-multipart starlette: requests @@ -802,21 +814,22 @@ deps = starlette: jinja2 starlette: httpx starlette-v0.16.0: httpx<0.28.0 - starlette-v0.28.0: httpx<0.28.0 {py3.6}-starlette: aiocontextvars fastapi-v0.79.1: fastapi==0.79.1 fastapi-v0.98.0: fastapi==0.98.0 fastapi-v0.117.1: fastapi==0.117.1 - fastapi-v0.135.1: fastapi==0.135.1 - fastapi-latest: fastapi==0.135.1 + fastapi-v0.135.3: fastapi==0.135.3 + fastapi-latest: fastapi==0.135.3 fastapi: httpx fastapi: pytest-asyncio fastapi: python-multipart fastapi: requests - fastapi: anyio<4 + fastapi: anyio>=3,<5 + fastapi: jinja2 fastapi-v0.79.1: httpx<0.28.0 fastapi-v0.98.0: httpx<0.28.0 + fastapi-v0.79.1: anyio<4 {py3.6}-fastapi: aiocontextvars @@ -824,11 +837,11 @@ deps = aiohttp-v3.4.4: aiohttp==3.4.4 aiohttp-v3.7.4: aiohttp==3.7.4 aiohttp-v3.10.11: aiohttp==3.10.11 - aiohttp-v3.13.3: aiohttp==3.13.3 - aiohttp-latest: aiohttp==3.13.3 + aiohttp-v3.13.5: aiohttp==3.13.5 + aiohttp-latest: aiohttp==3.13.5 aiohttp: pytest-aiohttp aiohttp-v3.10.11: pytest-asyncio - aiohttp-v3.13.3: pytest-asyncio + aiohttp-v3.13.5: pytest-asyncio aiohttp-latest: pytest-asyncio bottle-v0.12.25: bottle==0.12.25 @@ -1001,6 +1014,7 @@ setenv = pydantic_ai: _TESTPATH=tests/integrations/pydantic_ai pymongo: _TESTPATH=tests/integrations/pymongo pyramid: _TESTPATH=tests/integrations/pyramid + pyreqwest: _TESTPATH=tests/integrations/pyreqwest quart: _TESTPATH=tests/integrations/quart ray: _TESTPATH=tests/integrations/ray redis: _TESTPATH=tests/integrations/redis