diff --git a/.github/workflows/build_and_push.yaml b/.github/workflows/build_and_push.yaml
index 70e23c400..efd19e6c6 100644
--- a/.github/workflows/build_and_push.yaml
+++ b/.github/workflows/build_and_push.yaml
@@ -1,31 +1,28 @@
-# A workflow that builds and (optionally) pushes the Docker container image
-# artifacts for the application. The build action occurs on pull request events
-# that target the `main` branch, and the push action occurs only with tagged releases
-# and ticket branches.
+# A workflow that builds and pushes the Docker container image artifacts for
+# the application. The action occurs on new tags and when called from another
+# workflow.
 ---
 name: "Build and Push"
 
 "on":
-  pull_request:
-    branches:
-      - main
-    paths:
-      - 'src/lsst/cmservice/**'
   push:
     tags:
       - "*"
+  workflow_call:
   workflow_dispatch:
 
 jobs:
-  ci:
-    uses:
-      ./.github/workflows/ci.yaml
 
   build:
     name: "Build and Push Application Container Images"
-    needs:
-      - ci
     runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        include:
+          - target: cmservice
+            image: ${{ github.repository_owner }}/cm-service
+          - target: cmworker
+            image: ${{ github.repository_owner }}/cm-worker
     timeout-minutes: 20
 
     steps:
@@ -34,19 +31,10 @@ jobs:
           fetch-depth: 0
 
       - uses: lsst-sqre/build-and-push-to-ghcr@v1
-        id: build-service
         with:
           dockerfile: docker/Dockerfile
-          target: cmservice
-          image: ${{ github.repository }}
+          target: ${{ matrix.target }}
+          platforms: linux/amd64,linux/arm64
+          image: ${{ matrix.image }}
           github_token: ${{ secrets.GITHUB_TOKEN }}
-          push: ${{ github.ref_type == 'tag' || (github.ref_type == 'branch' && startsWith(github.ref_name, 'tickets/DM-')) }}
-
-      - uses: lsst-sqre/build-and-push-to-ghcr@v1
-        id: build-worker
-        with:
-          dockerfile: docker/Dockerfile
-          target: cmworker
-          image: ${{ github.repository }}
-          github_token: ${{ secrets.GITHUB_TOKEN }}
-          push: ${{ github.ref_type == 'tag' || (github.ref_type == 'branch' && startsWith(github.ref_name, 'tickets/DM-')) }}
+          push: true
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 71d26bf4e..f1c9c41d1 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -2,6 +2,7 @@
 # and when called from another workflow.
 ---
 name: "CI"
+
 "on":
   workflow_call:
   push:
@@ -13,8 +14,14 @@ env:
   UV_FROZEN: "1"
 
 jobs:
+  rebase-checker:
+    uses:
+      ./.github/workflows/rebase_checker.yaml
+
   lint:
     runs-on: ubuntu-latest
+    needs:
+      - rebase-checker
     steps:
 
       - name: Checkout Repository
@@ -28,13 +35,14 @@ jobs:
       - name: Run pre-commit
         uses: pre-commit/action@v3.0.1
 
-  test:
+  mypy:
     runs-on: ubuntu-latest
     strategy:
       matrix:
         python-version: ["3.11"]
+    needs:
+      - rebase-checker
     steps:
-
       - name: Checkout Repository
         uses: actions/checkout@v4
 
@@ -42,24 +50,25 @@ jobs:
         uses: astral-sh/setup-uv@v5
         with:
           version: "0.5.x"
-          enable_cache: true
+          enable-cache: true
           python-version: ${{ matrix.python-version }}
 
       - name: Install packages for testing
         run: uv sync --dev --frozen
 
       - name: Run tests
-        run: |
-          uv run playwright install
-          uv run make test
+        run: uv run make typing
 
-  mypy:
+  test:
     runs-on: ubuntu-latest
     strategy:
       matrix:
         python-version: ["3.11"]
-
+    needs:
+      - lint
+      - mypy
     steps:
+
       - name: Checkout Repository
         uses: actions/checkout@v4
 
@@ -67,11 +76,20 @@ jobs:
         uses: astral-sh/setup-uv@v5
         with:
           version: "0.5.x"
-          enable_cache: true
+          enable-cache: true
           python-version: ${{ matrix.python-version }}
 
       - name: Install packages for testing
         run: uv sync --dev --frozen
 
       - name: Run tests
-        run: uv run make typing
+        run: |
+          uv run playwright install
+          uv run make test
+
+
+  build-and-push:
+    needs:
+      - test
+    if: ${{ startsWith(github.ref_name, 'tickets/DM-') }}
+    uses: ./.github/workflows/build_and_push.yaml
diff --git a/.github/workflows/rebase_checker.yaml b/.github/workflows/rebase_checker.yaml
index 62aeca77e..c8cc710c3 100644
--- a/.github/workflows/rebase_checker.yaml
+++ b/.github/workflows/rebase_checker.yaml
@@ -1,7 +1,9 @@
 ---
-name: Check that 'main' is not merged into the development branch
+name: Rebase Checker
 
-on: pull_request
+"on":
+  workflow_call:
+  pull_request:
 
 jobs:
   call-workflow:
diff --git a/.gitignore b/.gitignore
index 72d6b659e..6795af6cc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,24 +1,176 @@
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
 # Byte-compiled / optimized / DLL files
 __pycache__/
 *.py[cod]
 *$py.class
 
+# C extensions
+*.so
+
 # Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
 *.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
 
 # Unit test / coverage reports
-.coverage*
 htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
 
-# notes files
-notes/
+# Translations
+*.mo
+*.pot
 
-# Backup filies
-*~
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+#   For a library or package, you might want to ignore these files since the code is
+#   intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+#   However, in case of collaboration, if having platform-specific dependencies or dependencies
+#   having no cross-platform support, pipenv may install dependencies that don't work, or not
+#   install all needed dependencies.
+#Pipfile.lock
+
+# UV
+#   Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
+#   This is especially recommended for binary packages to ensure reproducibility, and is more
+#   commonly ignored for libraries.
+uv.lock
+
+# poetry
+#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+#   This is especially recommended for binary packages to ensure reproducibility, and is more
+#   commonly ignored for libraries.
+#   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+#   in version control.
+#   https://pdm.fming.dev/latest/usage/project/#working-with-version-control
+.pdm.toml
+.pdm-python
+.pdm-build/
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
 
 # Environments
 .env
 .env.*
+.envrc
 .venv
 env/
 venv/
@@ -26,28 +178,57 @@ ENV/
 env.bak/
 venv.bak/
 
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
 # mypy
 .mypy_cache/
+.dmypy.json
+dmypy.json
 
-# ruff
-.ruff_cache/
+# Pyre type checker
+.pyre/
 
-#pytest
-.pytest_cache/
-output/
+# pytype static type analyzer
+.pytype/
 
-# macOS
-.DS_Store/
+# Cython debug symbols
+cython_debug/
 
-# vscode
-.vscode/
+# PyCharm
+#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+#  and can be added to the global gitignore or merged into this file.  For a more nuclear
+#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
 
-# development local sqlite file
-test_cm.db
+# PyPI configuration file
+.pypirc
+
+# Local Ignores
+output/
+prod_area/
+build/
 
 # temporary secrets files (do not commit these to git!)
 .secrets/
 
-build/
+# development local sqlite file
+test_cm.db
+
+# VS Code
+.vscode/
+
+# Bruno
 bruno/
-prod_area/
+
+# Ruff
+# Ruff usually installs a .gitignore file in its directory.
+.ruff_cache/
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index feb3b677e..ec9834b1f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -9,7 +9,7 @@ repos:
 
   - repo: https://github.com/astral-sh/ruff-pre-commit
     # Ruff version.
-    rev: v0.7.4
+    rev: v0.9.2
     hooks:
       - id: ruff
       - id: ruff
diff --git a/Makefile b/Makefile
index 1dcc69315..f6b3fb039 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,5 @@
 SHELL := /bin/bash
 GIT_BRANCH := $(shell git branch --show-current)
-PRERELEASE := $(shell if [[ $(GIT_BRANCH) =~ main ]]; then echo '--minor'; else echo '--no-tag --no-commit'; fi)
 PY_VENV := .venv/
 UV_LOCKFILE := uv.lock
 
@@ -63,7 +62,16 @@ uv:
 .PHONY: release
 release: export GIT_COMMIT_AUTHOR="$(shell git config user.name) <$(shell git config user.email)>"
 release:
-	uv run semantic-release version $(PRERELEASE) --no-push --no-vcs-release --skip-build --no-changelog
+	semantic-release version --no-push --no-vcs-release --skip-build --no-changelog --no-tag
+
+
+.PHONY: signed-release
+signed-release: release
+signed-release: export RELEASE_TAG=$(shell semantic-release version --print-last-released)
+signed-release:
+	git tag -d "$(RELEASE_TAG)" || true
+	git tag -s "$(RELEASE_TAG)" -m "Release $(RELEASE_TAG)"
+
 
 #------------------------------------------------------------------------------
 # Convenience targets to run pre-commit hooks ("lint") and mypy ("typing")
@@ -131,6 +139,16 @@ migrate: export DB__URL=postgresql://${PGHOST}/${PGDATABASE}
 migrate: run-compose
 	alembic upgrade head
 
+.PHONY: unmigrate
+unmigrate: export PGUSER=cm-service
+unmigrate: export PGDATABASE=cm-service
+unmigrate: export PGHOST=localhost
+unmigrate: export DB__PORT=$(shell docker compose port postgresql 5432 | cut -d: -f2)
+unmigrate: export DB__PASSWORD=INSECURE-PASSWORD
+unmigrate: export DB__URL=postgresql://${PGHOST}/${PGDATABASE}
+unmigrate: run-compose
+	alembic downgrade base
+
 
 #------------------------------------------------------------------------------
 # Targets for developers to debug running against local sqlite.  Can be used on
@@ -168,39 +186,14 @@ run-worker-sqlite:
 # for production and sqlite for development/debug.
 #------------------------------------------------------------------------------
 
-.PHONY: psql-usdf-dev
-psql-usdf-dev: export PGHOST=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get svc/cm-pg-lb -o jsonpath='{..ingress[0].ip}')'
-psql-usdf-dev: export PGPASSWORD=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get secret/cm-pg-app -o jsonpath='{.data.password}' | base64 --decode)
-psql-usdf-dev: export PGUSER=cm-service
-psql-usdf-dev: export PGDATABASE=cm-service
-psql-usdf-dev: ## Connect psql client to backend Postgres (shared USDF)
-	psql
-
-.PHONY: test-usdf-dev
-test-usdf-dev: DB__HOST=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get svc/cm-pg-lb -o jsonpath='{..ingress[0].ip}')'
-test-usdf-dev: export DB__URL=postgresql://cm-service@${DB__HOST}:5432/cm-service
-test-usdf-dev: export DB__PASSWORD=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get secret/cm-pg-app -o jsonpath='{.data.password}' | base64 --decode)
-test-usdf-dev: export DB__SCHEMA=cm_service_test
-test-usdf-dev:
-	pytest -vvv --cov=lsst.cmservice --cov-branch --cov-report=term --cov-report=html ${PYTEST_ARGS}
-
 .PHONY: run-usdf-dev
 run-usdf-dev:DB__HOST=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get svc/cm-pg-lb -o jsonpath='{..ingress[0].ip}')'
 run-usdf-dev: export DB__URL=postgresql://cm-service@${DB__HOST}:5432/cm-service
 run-usdf-dev: export DB__PASSWORD=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get secret/cm-pg-app -o jsonpath='{.data.password}' | base64 --decode)
 run-usdf-dev: export DB__ECHO=true
 run-usdf-dev:
-	alembic upgrade head
 	python3 -m lsst.cmservice.main
 
-.PHONY: run-worker-usdf-dev
-run-worker-usdf-dev: DB__HOST=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get svc/cm-pg-lb -o jsonpath='{..ingress[0].ip}')
-run-worker-usdf-dev: export DB__URL=postgresql://cm-service@${DB__HOST}:5432/cm-service
-run-worker-usdf-dev: export DB__PASSWORD=$(shell kubectl --cluster=usdf-cm-dev -n cm-service get secret/cm-pg-app -o jsonpath='{.data.password}' | base64 --decode)
-run-worker-usdf-dev: export DB__ECHO=true
-run-worker-usdf-dev:
-	python3 -m lsst.cmservice.daemon
-
 get-env-%: DB__HOST=$(shell kubectl --cluster=$* -n cm-service get svc/cm-pg-lb -o jsonpath='{..ingress[0].ip}')
 get-env-%: export DB__URL=postgresql://cm-servicer@${DB__HOST}:5432/cm-service
 get-env-%: export DB__PASSWORD=$(shell kubectl --cluster=$* -n cm-service get secret/cm-pg-app -o jsonpath='{.data.password}' | base64 --decode)
diff --git a/README.md b/README.md
index 325787a6d..89c3d54db 100644
--- a/README.md
+++ b/README.md
@@ -49,11 +49,12 @@ follows:
 Additional developer conveniences:
 
 * Browse the integrated online ReST API documentation while the service is running at
-  http://localhost:8080/cm-service/v1/docs.
+  http://localhost:8080/docs.
 
 * Run the pytest test suite at any point with `make test`.  This will launch subsidiary containers if
   necessary via Docker Compose, or will make use of any that may already be running.  Tests are performed in
   their own Postgres schema, so as not interfere with debugging state in a running debug service instance.
+  (You may run `docker compose down -v` to clean up completely between runs.)
 
 * To run the playwright tests, add `--run-playwright` to the pytest arguments
 
@@ -83,95 +84,3 @@ Additional developer conveniences:
 
 * `uv` uses a global package cache for speed and efficiency; you manage this cache with `uv cache prune` or
   `uv cache clean` for the nuclear option.
-
-## Release Management
-
-This project is developed using a Trunk-Based Development pattern, where the trunk branch is named `main`.
-Developers should work in short-lived feature branches and commit their work to the trunk in accordance with
-the [LSST Development Workflow](https://developer.lsst.io/work/flow.html).
-
-Releases are performed at an unspecified cadence, to be no shorter than 1 week and subject to these rules:
-
-- Releases are named according to their semantic version (major.minor.patch).
-- Releases are made by adding a named tag to the trunk branch.
-- Each release will increment the minor version and set the patch level to 0, e.g., `1.0.12` -> `1.1.0`
-- If a bugfix commit needs to be added to a release, then a retroactive branch will be created from the
-  release tag; the commit is cherry-picked into the release branch and a new tag is written with an incremented
-  patch level, e.g., `1.23.0` -> `1.23.1`.
-- The major version is incremented only in the presence of user-facing breaking changes.
-
-This project uses `python-semantic-release` to manage releases. A release should be triggered by any ticket branch
-being merged into `main`. A release must increment the application version according to semantic versioning (i.e.,
-the use of major-minor-patch version tokens); and must create a matching git tag.
-
-The `make release` target is designed to shepherd the manual release management process:
-
-1. The version number in `src/lsst/cmservice/__init__.py:__version__` is written according to the new version.
-
-1. The updated version file is committed to git.
-
-1. If on `main`, a git tag is created. Git tags are not created for prerelease versions (releases made on
-   user or ticket branches.)
-
-## Debugging
-
-### VSCode
-
-When using VSCode, you can use the debugger built into the Python extension to start an instance of the service
-in a debug context by creating a `.vscode/launch.json` file in the Workspace. This configuration file
-tells VSCode how to start an application for debugging, after which VSCode's breakpoints and other debug tools
-are available.
-
-This example `launch.json` file illustrates the launch of a debuggable CM Service and Daemon instances using `usdf-cm-dev`
-resources:
-
-```
-{
-  "version": "0.2.0",
-  "configurations": [
-    {
-      "name": "Debug: CM-Service [usdf-cm-dev]",
-      "type": "debugpy",
-      "request": "launch",
-      "module": "uvicorn",
-      "args": [
-        "--port", "8080", "--reload",
-        "lsst.cmservice.main:app"
-      ],
-      "envFile": "${workspaceFolder}/.env.usdf-cm-dev"
-    },
-    {
-      "name": "Debug: User Daemon [usdf-cm-dev]",
-      "type": "debugpy",
-      "request": "launch",
-      "module": "lsst.cmservice.cli.client",
-      "args": ["queue", "daemon", "--row_id", "${input:rowID}"],
-      "envFile": "${workspaceFolder}/.env.usdf-cm-dev"
-    },
-    {
-      "name": "Debug: System Daemon [usdf-cm-dev]",
-      "type": "debugpy",
-      "request": "launch",
-      "module": "lsst.cmservice.daemon",
-      "envFile": "${workspaceFolder}/.env.usdf-cm-dev"
-    }
-  ],
-  "inputs": [
-    {
-      "id": "rowID",
-      "description": "A Campaign Row ID for the debug client queue",
-      "type": "promptString",
-      "default": "1"
-    }
-  ]
-}
-```
-
-Note that this configuration references an `envFile`; there is a `make` target for generating
-`.env` files that can be consumed by VSCode debug configurations: `make get-env-<k8s cluster>`
-(e.g., `make get-env-usdf-cm-dev` will produce a file `.env.usdf-cm-dev` with environment variables
-set to values appropriate for services running in the named Kubernetes cluster). Otherwise, you may
-create a custom `.env` file and reference it from Launch Configuration instead.
-
-The debug Daemon is launched using a prompted value for the `--row_id` parameter, which will cause
-VSCode to open a prompt for this input.
diff --git a/docker-compose.yaml b/docker-compose.yaml
index 300b5c428..bf7eb1653 100644
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -3,7 +3,7 @@
 
 name: "${USER}-cm-service"
 services:
-  init-db:
+  migratedb:
     profiles:
       - full
       - server
@@ -46,13 +46,13 @@ services:
     networks:
       - cmservice
     depends_on:
-      init-db:
+      migratedb:
         condition: service_completed_successfully
 
   cmworker:
     profiles:
       - full
-      - worker
+      - daemon
     build:
       context: .
       dockerfile: docker/Dockerfile
@@ -66,7 +66,7 @@ services:
     networks:
       - cmservice
     depends_on:
-      init-db:
+      migratedb:
         condition: service_completed_successfully
 
   postgresql:
diff --git a/docker/Dockerfile b/docker/Dockerfile
index b958eb241..c7b94322b 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -32,6 +32,7 @@ export DEBIAN_FRONTEND=noninteractive
 
 apt-get update
 apt-get -y upgrade
+apt-get -y install libexpat1
 apt-get clean
 rm -rf /var/lib/apt/lists/*
 ENDRUN
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
new file mode 100644
index 000000000..3d78cfce5
--- /dev/null
+++ b/docs/CONTRIBUTING.md
@@ -0,0 +1,46 @@
+# Contributing
+
+- Use [conventional commit](https://www.conventionalcommits.org/en/v1.0.0/) messages when contributing to this repository.
+- This repository generally aligns with the [Angular Commit Message Format](https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit) to the extent that Releases (see below) parse commit logs to determine the type of version bump:
+  - `feat`: indicates a `minor` version bump.
+  - `fix`: indicates a `patch` version bump.
+  - `BREAKING CHANGE:` in the commit message body indicates a `major` version bump.
+- Please rebase commits in branches to the minimum necessary. Bugfix commmits (`fix: ...`) should be standalone and focused
+  commits that can be back-ported to other branches via cherry-picking.
+
+# Release Management
+
+This project is developed using a Trunk-Based Development pattern, where the trunk branch is named `main`.
+Developers should work in short-lived feature branches and commit their work to the trunk in accordance with
+the [LSST Development Workflow](https://developer.lsst.io/work/flow.html).
+
+Releases are performed at an unspecified cadence, to be no shorter than 1 week and subject to these rules:
+
+- Releases are named according to their semantic version (major.minor.patch).
+- Releases are made by adding a named tag to the trunk branch.
+- Each release will increment the minor version and set the patch level to 0, e.g., `1.0.12` -> `1.1.0`
+- If a bugfix commit needs to be added to a release, then a retroactive branch will be created from the
+  release tag; the commit is cherry-picked into the release branch and a new tag is written with an incremented
+  patch level, e.g., `1.23.0` -> `1.23.1`.
+- The major version is incremented only in the presence of user-facing breaking changes.
+
+This project uses `python-semantic-release` to manage releases. A release may be triggered by any ticket branch
+being merged into `main`. A release must increment the application version according to semantic versioning (i.e.,
+the use of major-minor-patch version tokens); and must create a matching git tag.
+
+A manual release may be made on any ticket branch ending in `release`, e.g., `tickets/DM-XXXXX/release` by using
+the make targets described below.
+
+The `make release` target is designed to shepherd the manual release management process:
+
+1. The version number in `src/lsst/cmservice/__init__.py:__version__` is written according to the new version.
+1. The updated version file is committed to git.
+1. A tag is created for the current release commit.
+
+The `make signed-release` target does the above but creates a *signed* tag, so only authors with
+correct GPG keys may create a signed release.
+
+*Take care to push release tags (signed or not) only after the release branch has been merged to main.*
+
+A pre-release may be made in a `u/*` or a `ticket/*` branch by calling `make release`, and the version will be
+bumped according to pre-release rules.
diff --git a/docs/DEBUGGING.md b/docs/DEBUGGING.md
new file mode 100644
index 000000000..8ea0ddb40
--- /dev/null
+++ b/docs/DEBUGGING.md
@@ -0,0 +1,62 @@
+# Debugging
+
+## VSCode
+
+When using VSCode, you can use the debugger built into the Python extension to start an instance of the service
+in a debug context by creating a `.vscode/launch.json` file in the Workspace. This configuration file
+tells VSCode how to start an application for debugging, after which VSCode's breakpoints and other debug tools
+are available.
+
+This example `launch.json` file illustrates the launch of a debuggable CM Service and Daemon instances using `usdf-cm-dev`
+resources:
+
+```
+{
+  "version": "0.2.0",
+  "configurations": [
+    {
+      "name": "Debug: CM-Service [usdf-cm-dev]",
+      "type": "debugpy",
+      "request": "launch",
+      "module": "uvicorn",
+      "args": [
+        "--port", "8080", "--reload",
+        "lsst.cmservice.main:app"
+      ],
+      "envFile": "${workspaceFolder}/.env.usdf-cm-dev"
+    },
+    {
+      "name": "Debug: User Daemon [usdf-cm-dev]",
+      "type": "debugpy",
+      "request": "launch",
+      "module": "lsst.cmservice.cli.client",
+      "args": ["queue", "daemon", "--row_id", "${input:rowID}"],
+      "envFile": "${workspaceFolder}/.env.usdf-cm-dev"
+    },
+    {
+      "name": "Debug: System Daemon [usdf-cm-dev]",
+      "type": "debugpy",
+      "request": "launch",
+      "module": "lsst.cmservice.daemon",
+      "envFile": "${workspaceFolder}/.env.usdf-cm-dev"
+    }
+  ],
+  "inputs": [
+    {
+      "id": "rowID",
+      "description": "A Campaign Row ID for the debug client queue",
+      "type": "promptString",
+      "default": "1"
+    }
+  ]
+}
+```
+
+Note that this configuration references an `envFile`; there is a `make` target for generating
+`.env` files that can be consumed by VSCode debug configurations: `make get-env-<k8s cluster>`
+(e.g., `make get-env-usdf-cm-dev` will produce a file `.env.usdf-cm-dev` with environment variables
+set to values appropriate for services running in the named Kubernetes cluster). Otherwise, you may
+create a custom `.env` file and reference it from Launch Configuration instead.
+
+The debug Daemon is launched using a prompted value for the `--row_id` parameter, which will cause
+VSCode to open a prompt for this input.
diff --git a/.github/README.md b/docs/WORKFLOWS.md
similarity index 100%
rename from .github/README.md
rename to docs/WORKFLOWS.md
diff --git a/examples/empty_config.yaml b/examples/empty_config.yaml
index 8f7febeae..49a0bd4f1 100644
--- a/examples/empty_config.yaml
+++ b/examples/empty_config.yaml
@@ -29,9 +29,6 @@
           prod_area: 'output/archive'
           data_query: "instrument = 'HSC'"
           lsst_version: "${WEEKLY}"
-          bps_script_template: bps_panda_script_template
-          bps_yaml_template: bps_yaml_template
-          manifest_script_template: manifest_script_template
 - Specification:
       name: base
       spec_aliases:
diff --git a/examples/example_standard_elements.yaml b/examples/example_standard_elements.yaml
index 5cdd21cba..2f54e86e6 100644
--- a/examples/example_standard_elements.yaml
+++ b/examples/example_standard_elements.yaml
@@ -145,10 +145,6 @@
                     inputs: ["{campaign_output}", "{campaign_input}", "{campaign_resource_usage}"]
                     output: "{campaign_public_output}"
       data:
-          bps_core_script_template: bps_core_script_template
-          bps_core_yaml_template: bps_core_yaml_template
-          manifest_script_template: stack_script_template
-          resource_usage_script_template: stack_script_template
           lsst_version: MUST_OVERRIDE
           lsst_distrib_dir: /cvmfs/sw.lsst.eu/linux-x86_64/lsst_distrib
 # Campagin Template for fixed inputs
@@ -189,10 +185,6 @@
                     inputs: ["{campaign_output}", "{campaign_input}"]
                     output: "{campaign_public_output}"
       data:
-          bps_core_script_template: bps_core_script_template
-          bps_core_yaml_template: bps_core_yaml_template
-          manifest_script_template: stack_script_template
-          resource_usage_script_template: stack_script_template
           lsst_version: MUST_OVERRIDE
           lsst_distrib_dir: /cvmfs/sw.lsst.eu/linux-x86_64/lsst_distrib
 # Campaign template for base campaign+hips maps
@@ -263,11 +255,6 @@
                     inputs: ["{campaign_output}", "{campaign_input}", "{campaign_resource_usage}", "{campaign_hips_maps}"]
                     output: "{campaign_public_output}"
       data:
-          bps_core_script_template: bps_core_script_template
-          bps_core_yaml_template: bps_core_yaml_template
-          manifest_script_template: stack_script_template
-          resource_usage_script_template: stack_script_template
-          hips_maps_script_template: stack_script_template
           lsst_version: MUST_OVERRIDE
           lsst_distrib_dir: /cvmfs/sw.lsst.eu/linux-x86_64/lsst_distrib
 # Campaign Template for fixed inputs which also generates HIPS maps
@@ -315,10 +302,5 @@
                     inputs: ["{campaign_output}", "{campaign_input}", "{campaign_resource_usage}", "{campaign_hips_maps}"]
                     output: "{campaign_public_output}"
       data:
-          bps_core_script_template: bps_core_script_template
-          bps_core_yaml_template: bps_core_yaml_template
-          manifest_script_template: stack_script_template
-          resource_usage_script_template: stack_script_template
-          hips_maps_script_template: stack_script_template
           lsst_version: MUST_OVERRIDE
           lsst_distrib_dir: /cvmfs/sw.lsst.eu/linux-x86_64/lsst_distrib
diff --git a/examples/example_standard_scripts.yaml b/examples/example_standard_scripts.yaml
index 14fe84d45..3eafbcc46 100644
--- a/examples/example_standard_scripts.yaml
+++ b/examples/example_standard_scripts.yaml
@@ -1,23 +1,3 @@
-# Template shell script fragment for running BPS
-- ScriptTemplate:
-      name: bps_core_script_template
-      file_path: ${CM_CONFIGS}/templates/example_bps_core_script_template.yaml
-# Template shell script fragment for running BPS under PANDA
-- ScriptTemplate:
-      name: bps_panda_script_template
-      file_path: ${CM_CONFIGS}/templates/example_bps_panda_script_template.yaml
-# Template shell script fragment for running BPS under HTCondor
-- ScriptTemplate:
-      name: bps_htcondor_script_template
-      file_path: ${CM_CONFIGS}/templates/example_bps_htcondor_script_template.yaml
-# Template shell script fragment for using stack
-- ScriptTemplate:
-      name: stack_script_template
-      file_path: ${CM_CONFIGS}/templates/example_stack_script_template.yaml
-# Template yaml config for running bps
-- ScriptTemplate:
-      name: bps_core_yaml_template
-      file_path: ${CM_CONFIGS}/templates/example_bps_core_yaml_template.yaml
 # define the null Script
 - SpecBlock:
       name: null_script
@@ -70,7 +50,6 @@
       handler: lsst.cmservice.handlers.jobs.PandaScriptHandler
       data:
           bps_wms_yaml_file: "${CTRL_BPS_PANDA_DIR}/config/bps_usdf.yaml"
-          bps_wms_script_template: bps_panda_script_template
 # Run a bps report script
 - SpecBlock:
       name: bps_panda_report_script
@@ -79,9 +58,6 @@
 - SpecBlock:
       name: bps_htcondor_submit_script
       handler: lsst.cmservice.handlers.jobs.HTCondorScriptHandler
-      data:
-          bps_wms_yaml_file: "${CM_CONFIGS}/stack_files/bps_htcondor_usdf.yaml"
-          bps_wms_script_template: bps_htcondor_script_template
 # Run a bps report script
 - SpecBlock:
       name: bps_htcondor_report_script
diff --git a/examples/stack_files/bps_htcondor_usdf.yaml b/examples/stack_files/bps_htcondor_usdf.yaml
deleted file mode 100644
index df5451746..000000000
--- a/examples/stack_files/bps_htcondor_usdf.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-# computeSite:
-site:
-  s3df:
-    profile:
-      condor:
-        +Walltime: 7200
-
-# Let's turn on the memory multiplier
-memoryMultiplier: 4.
-numberOfRetries: 3
-memoryLimit: 400000
-
-# Condor backend stuff
-wmsServiceClass: lsst.ctrl.bps.htcondor.HTCondorService
diff --git a/examples/templates/example_bps_core_script_template.yaml b/examples/templates/example_bps_core_script_template.yaml
deleted file mode 100644
index 6384c65da..000000000
--- a/examples/templates/example_bps_core_script_template.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-text: "#!/usr/bin/env -S -i CM_CONFIGS=\"${CM_CONFIGS}\" HOME=\"${HOME}\" bash\n
-
-# The shebang lines above are needed b/c setup lsst_distrib is putting\n
-# the lsst python _after_ the virtual env python in the PATH, which\n
-# is causing errors\n
-
-# This is needed to define butler aliases\n
-export DAF_BUTLER_REPOSITORY_INDEX=/sdf/group/rubin/shared/data-repos.yaml\n
-
-# setup LSST env.\n
-export LSST_VERSION='{lsst_version}'\n
-export LSST_DISTRIB_DIR='{lsst_distrib_dir}'\n
-source ${LSST_DISTRIB_DIR}/${LSST_VERSION}/loadLSST.bash\n
-setup lsst_distrib\n
-
-"
diff --git a/examples/templates/example_bps_core_yaml_template.yaml b/examples/templates/example_bps_core_yaml_template.yaml
deleted file mode 100644
index b56e35813..000000000
--- a/examples/templates/example_bps_core_yaml_template.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-# turn off the -o option in pipetask commands
-pipetaskOutput: ""
-
-executionButler:
-  requestMemory: 64000
-  queue: "SLAC_Rubin_Merge"
-  # turn off chaining in the execution butler because
-  # no output collection
-  command2: ""
-  command3: ""
diff --git a/examples/templates/example_bps_htcondor_script_template.yaml b/examples/templates/example_bps_htcondor_script_template.yaml
deleted file mode 100644
index d22397e78..000000000
--- a/examples/templates/example_bps_htcondor_script_template.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-text: "
-
-# Setup for using condor on slac farm\n
-export _condor_SEC_CLIENT_AUTHENTICATION_METHODS=FS,FS_REMOTE\n
-export _condor_COLLECTOR_HOST=sdfrome001.sdf.slac.stanford.edu\n
-export _condor_SCHEDD_HOST=sdfrome001.sdf.slac.stanford.edu\n
-export _condor_DAGMAN_MANAGER_JOB_APPEND_GETENV=true\n
-"
diff --git a/examples/templates/example_bps_panda_script_template.yaml b/examples/templates/example_bps_panda_script_template.yaml
deleted file mode 100644
index 09776db7c..000000000
--- a/examples/templates/example_bps_panda_script_template.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-text: "# setup PanDA env.\n
-latest_panda=$(ls -td /cvmfs/sw.lsst.eu/linux-x86_64/panda_env/v* | head -1)\n
-setupScript=${latest_panda}/setup_panda_usdf.sh\n
-source $setupScript ${WEEKLY}\n
-
-env | grep PANDA\n
-
-# let's drop a panda_auth status here for kicks\n
-panda_auth status\n
-"
diff --git a/examples/templates/example_stack_script_template.yaml b/examples/templates/example_stack_script_template.yaml
deleted file mode 100644
index 236af89c3..000000000
--- a/examples/templates/example_stack_script_template.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-text: "#!/usr/bin/env -S -i CM_CONFIGS=\"${CM_CONFIGS}\" HOME=\"${HOME}\" bash\n
-
-# The shebang lines above are needed b/c setup lsst_distrib in putting\n
-# the lsst python _after_ the virtual env python in the PATH, which\n
-# is causing errors\n
-
-# This is needed to define butler aliases\n
-export DAF_BUTLER_REPOSITORY_INDEX=/sdf/group/rubin/shared/data-repos.yaml\n
-
-# setup LSST env.\n
-export LSST_VERSION='{lsst_version}'\n
-export LSST_DISTRIB_DIR='{lsst_distrib_dir}'\n
-source ${LSST_DISTRIB_DIR}/${LSST_VERSION}/loadLSST.bash\n
-setup lsst_distrib\n
-
-"
diff --git a/pyproject.toml b/pyproject.toml
index af03e4038..0a8a5ebe8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -17,7 +17,7 @@ classifiers = [
     "Operating System :: POSIX",
     "Typing :: Typed",
 ]
-requires-python = ">=3.11"
+requires-python = ">=3.11,<3.13"
 dynamic = ["version"]
 
 dependencies = [
@@ -35,11 +35,11 @@ dependencies = [
     "lsst-daf-butler>=28.2024.5000",
     "lsst-pipe-base>=28.2024.5000",
     "numpy==2.1.*",
-    "pause==0.3.*",
     "psycopg2-binary==2.9.*",
     "pydantic==2.10.*",
     "pydantic-settings==2.7.*",
     "python-multipart==0.0.*",
+    "rich==13.9.*",
     "structlog==24.4.*",
     "tabulate==0.9.*",
     "sqlalchemy[asyncio]==2.0.*",
@@ -211,6 +211,10 @@ tag_format = "{version}"
 match = "main"
 prerelease = false
 
+[tool.semantic_release.branches.release]
+match = "^tickets/DM-\\d+(.*)/release$"
+prerelease = false
+
 [tool.semantic_release.branches.ticket]
 match = "^tickets/DM-\\d+(.*)$"
 prerelease_token = "rc"
diff --git a/script/README.md b/script/README.md
index 9efdf2c61..b7d672c45 100644
--- a/script/README.md
+++ b/script/README.md
@@ -4,3 +4,7 @@ required or used by the application runtime.
 ## bootstrap_uv.sh
 
 This script bootstraps the `uv` tool if it is not present in your working environment.
+
+## get_nodes.sh
+
+This script runs an allocate nodes command on a loop.
diff --git a/script/bootstrap_uv b/script/bootstrap_uv
index 662fbefed..0a447273d 100755
--- a/script/bootstrap_uv
+++ b/script/bootstrap_uv
@@ -21,7 +21,7 @@ fi
 
 UV_OS="$(uname -s)"
 UV_ARCH="$(uname -m)"
-UV_VERSION="0.5.8"
+UV_VERSION="0.5.18"
 UV_RELEASE="https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-${UV_ARCH}-unknown-linux-gnu.tar.gz"
 XDG_BIN_HOME=${XDG_BIN_HOME:-$HOME/.local/bin}
 XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config}
diff --git a/get_nodes.sh b/script/get_nodes.sh
similarity index 100%
rename from get_nodes.sh
rename to script/get_nodes.sh
diff --git a/src/lsst/cmservice/__init__.py b/src/lsst/cmservice/__init__.py
index 49fa3ac5a..5ccb0db70 100644
--- a/src/lsst/cmservice/__init__.py
+++ b/src/lsst/cmservice/__init__.py
@@ -2,4 +2,4 @@
 
 __all__ = ["__version__"]
 
-__version__ = "0.2.0-rc.1"
+__version__ = "0.2.0"
diff --git a/src/lsst/cmservice/cli/options.py b/src/lsst/cmservice/cli/options.py
index 90a083b14..4c95f7d3e 100644
--- a/src/lsst/cmservice/cli/options.py
+++ b/src/lsst/cmservice/cli/options.py
@@ -93,7 +93,7 @@ class DictParamType(click.ParamType):
 
     name = "dictionary"
 
-    def convert(  # pylint:  disable=inconsistent-return-statements
+    def convert(
         self,
         value: Any,
         param: click.Parameter | None,
@@ -168,8 +168,8 @@ def __call__(self: "PartialOption", *param_decls: str, **attrs: Any) -> Callable
 class OutputEnum(Enum):
     """Options for output format"""
 
-    yaml = auto()  # pylint: disable=invalid-name
-    json = auto()  # pylint: disable=invalid-name
+    yaml = auto()
+    json = auto()
 
 
 output = PartialOption(
diff --git a/src/lsst/cmservice/client/client.py b/src/lsst/cmservice/client/client.py
index 7ebc5738a..d3473fd10 100644
--- a/src/lsst/cmservice/client/client.py
+++ b/src/lsst/cmservice/client/client.py
@@ -31,7 +31,7 @@
 __all__ = ["CMClient"]
 
 
-class CMClient:  # pylint: disable=too-many-instance-attributes
+class CMClient:
     """Interface for accessing remote cm-service."""
 
     def __init__(self: CMClient) -> None:
@@ -41,6 +41,12 @@ def __init__(self: CMClient) -> None:
             client_kwargs["headers"] = {"Authorization": f"Bearer {client_config.auth_token}"}
         if "timeout" in client_config.model_fields_set:  # pragma: no cover
             client_kwargs["timeout"] = client_config.timeout
+        if "cookies" in client_config.model_fields_set:  # pragma: no cover
+            cookies = httpx.Cookies()
+            if client_config.cookies:
+                for cookie in client_config.cookies:
+                    cookies.set(name=cookie.name, value=cookie.value)
+            client_kwargs["cookies"] = cookies
         self._client = httpx.Client(**client_kwargs)
 
         self.production = CMProductionClient(self)
diff --git a/src/lsst/cmservice/client/clientconfig.py b/src/lsst/cmservice/client/clientconfig.py
index 5c4e9ad47..7a53a34d0 100644
--- a/src/lsst/cmservice/client/clientconfig.py
+++ b/src/lsst/cmservice/client/clientconfig.py
@@ -1,11 +1,16 @@
 from typing import Any
 
-from pydantic import Field, field_validator
+from pydantic import BaseModel, Field, field_validator
 from pydantic_settings import BaseSettings, SettingsConfigDict
 
 __all__ = ["ClientConfiguration", "client_config"]
 
 
+class ClientCookie(BaseModel):
+    name: str
+    value: str
+
+
 class ClientConfiguration(BaseSettings):
     """Configuration for cm-client."""
 
@@ -21,6 +26,14 @@ class ClientConfiguration(BaseSettings):
         validation_alias="CM_TOKEN",
     )
 
+    cookies: list[ClientCookie] | None = Field(
+        description=(
+            "Comma separated list of pipe-separated cookie names and values, e.g., `name|value,name|value`"
+        ),
+        default=None,
+        validation_alias="CM_COOKIES",
+    )
+
     timeout: float | None = Field(
         default=None,
         validation_alias="CM_TIMEOUT",
@@ -34,6 +47,13 @@ def validate_timeout(cls, v: Any) -> float | None:
             return None
         return v
 
+    @field_validator("cookies", mode="before", check_fields=True)
+    @classmethod
+    def validate_cookies(cls, v: Any) -> list[ClientCookie] | None:
+        if v is None:  # pragma: no cover
+            return v
+        return [ClientCookie(name=n, value=v) for n, v in [a.split("|") for a in v.split(",")]]
+
 
 client_config = ClientConfiguration()
 """Configuration for cm-client."""
diff --git a/src/lsst/cmservice/client/queues.py b/src/lsst/cmservice/client/queues.py
index 39a26557b..c420c4352 100644
--- a/src/lsst/cmservice/client/queues.py
+++ b/src/lsst/cmservice/client/queues.py
@@ -3,10 +3,10 @@
 from __future__ import annotations
 
 from datetime import datetime, timedelta
+from time import sleep
 from typing import TYPE_CHECKING
 
 import httpx
-import pause
 from pydantic import TypeAdapter, ValidationError
 
 from .. import db, models
@@ -133,7 +133,7 @@ def pause_until_next_check(
             # In unit tests we set queue.interval to zero
             # so don't ever get to these lines
             print("pausing")
-            pause.until(next_check)
+            sleep(sleep_time)
 
     def daemon(
         self,
diff --git a/src/lsst/cmservice/common/bash.py b/src/lsst/cmservice/common/bash.py
index 332ef6f0f..866da8dbb 100644
--- a/src/lsst/cmservice/common/bash.py
+++ b/src/lsst/cmservice/common/bash.py
@@ -7,6 +7,7 @@
 import yaml
 from anyio import Path, open_file, open_process
 from anyio.streams.text import TextReceiveStream
+from jinja2 import Environment, PackageLoader
 
 from ..config import config
 from .enums import StatusEnum
@@ -169,6 +170,7 @@ async def check_stamp_file(
 async def write_bash_script(
     script_url: str | Path,
     command: str,
+    values: dict,
     **kwargs: Any,
 ) -> Path:
     """Utility function to write a bash script for later execution.
@@ -181,20 +183,11 @@ async def write_bash_script(
     command: `str`
         Main command line(s) in the script
 
+    values: `dict`
+        Mapping of potential template variables to values.
+
     Keywords
     --------
-    prepend: `str | None`
-        Text to prepend before command
-
-    append: `str | None`
-        Test to append after command
-
-    stamp: `str | None`
-        Text to echo to stamp file when script completes
-
-    stamp_url: `str | None`
-        Stamp file to write to when script completes
-
     fake: `str | None`
         Echo command instead of running it
 
@@ -202,13 +195,16 @@ async def write_bash_script(
         Prefix to script_url used when rolling back
         processing. Will default to CWD (".").
 
+
     Returns
     -------
     script_url : `anyio.Path`
         The path to the newly written script
     """
-    prepend = kwargs.get("prepend")
-    append = kwargs.get("append")
+    # Get the yaml template using package lookup
+    template_environment = Environment(loader=PackageLoader("lsst.cmservice"))
+    bash_template = template_environment.get_template("wms_submit_sh.j2")
+
     fake = kwargs.get("fake")
     rollback_prefix = Path(kwargs.get("rollback", "."))
 
@@ -218,8 +214,17 @@ async def write_bash_script(
         command = f"echo '{command}'"
 
     await script_path.parent.mkdir(parents=True, exist_ok=True)
-    contents = (prepend if prepend else "") + "\n" + command + "\n" + (append if append else "")
 
-    async with await open_file(script_path, "w") as fout:
-        await fout.write(contents)
+    template_values = {
+        "command": command,
+        **values,
+    }
+
+    try:
+        # Render bash script template to `script_path`
+        bash_output = bash_template.render(template_values)
+        await Path(script_path).write_text(bash_output)
+    except Exception as e:
+        raise RuntimeError(f"Error writing a script to run BPS job {script_url}; threw {e}")
+
     return script_path
diff --git a/src/lsst/cmservice/common/butler.py b/src/lsst/cmservice/common/butler.py
index 343f530b9..a51ecaacf 100644
--- a/src/lsst/cmservice/common/butler.py
+++ b/src/lsst/cmservice/common/butler.py
@@ -2,11 +2,71 @@
 
 from functools import partial
 
-from anyio import to_thread
+import yaml
+from anyio import Path, to_thread
+from sqlalchemy.engine import url
 
-from lsst.daf.butler import Butler, MissingCollectionError
+from lsst.daf.butler import Butler, ButlerConfig, ButlerRepoIndex
+from lsst.daf.butler._exceptions import MissingCollectionError
+from lsst.resources import ResourcePathExpression
+from lsst.utils.db_auth import DbAuth
 
-from ..common import errors
+from ..config import config
+from . import errors
+from .logging import LOGGER
+
+logger = LOGGER.bind(module=__name__)
+
+
+BUTLER_REPO_INDEX = ButlerRepoIndex()
+"""An index of all known butler repositories, as populated by the
+DAF_BUTLER_REPOSITORIES environment variable.
+"""
+
+
+async def get_butler_config(repo: str, *, without_datastore: bool = False) -> ButlerConfig:
+    """Create a butler config object for a repo known to the service's
+    environment.
+    """
+
+    try:
+        repo_uri: ResourcePathExpression = BUTLER_REPO_INDEX.get_repo_uri(label=repo)
+    except KeyError:
+        # No such repo known to the service
+        logger.warning("Butler repo %s not known to environment.", repo)
+        repo_uri = repo
+
+    try:
+        bc_f = partial(
+            ButlerConfig,
+            other=repo_uri,
+            without_datastore=without_datastore,
+        )
+        bc = await to_thread.run_sync(bc_f)
+    except FileNotFoundError:
+        # No such repo known to Butler
+        logger.error("Butler repo %s not known.", repo)
+        raise RuntimeError("Unknown Butler Repo %s", repo)
+
+    try:
+        db_auth_info = yaml.safe_load(await Path(config.butler.authentication_file).read_text())
+    except FileNotFoundError:
+        logger.error("No Butler Registry authentication secrets found.")
+        # delegate db auth info discovery to normal toolchain
+        return bc
+
+    db_url = url.make_url(bc["registry"]["db"])
+    db_auth = DbAuth(authList=db_auth_info).getAuth(
+        dialectname=db_url.drivername,
+        username=db_url.username,
+        host=db_url.host,
+        port=db_url.port,
+        database=db_url.database,
+    )
+
+    bc[".registry.username"] = db_auth[0]
+    bc[".registry.password"] = db_auth[1]
+    return bc
 
 
 async def remove_run_collections(
@@ -28,6 +88,7 @@ async def remove_run_collections(
     fake_reset: bool
         Allow for missing butler
     """
+    fake_reset = fake_reset or config.butler.mock
     try:
         butler_f = partial(
             Butler.from_config,
@@ -68,6 +129,7 @@ async def remove_non_run_collections(
     fake_reset: bool
         Allow for missing butler
     """
+    fake_reset = fake_reset or config.butler.mock
     try:
         butler_f = partial(
             Butler.from_config,
@@ -109,6 +171,7 @@ async def remove_collection_from_chain(
     fake_reset: bool
         Allow for missing butler
     """
+    fake_reset = fake_reset or config.butler.mock
     if fake_reset:
         return
     raise NotImplementedError
@@ -137,6 +200,7 @@ async def remove_datasets_from_collections(
     fake_reset: bool
         Allow for missing butler
     """
+    fake_reset = fake_reset or config.butler.mock
     if fake_reset:
         return
     raise NotImplementedError
diff --git a/src/lsst/cmservice/common/daemon.py b/src/lsst/cmservice/common/daemon.py
index 3182a715e..c3e116d84 100644
--- a/src/lsst/cmservice/common/daemon.py
+++ b/src/lsst/cmservice/common/daemon.py
@@ -1,37 +1,134 @@
 from datetime import datetime, timedelta
 
-import structlog
 from sqlalchemy.ext.asyncio import async_scoped_session
 from sqlalchemy.future import select
 
 from ..config import config
 from ..db.queue import Queue
 from ..db.script import Script
+from .htcondor import build_htcondor_submit_environment, import_htcondor
+from .logging import LOGGER
 
-logger = structlog.get_logger(__name__)
+logger = LOGGER.bind(module=__name__)
 
 
 async def daemon_iteration(session: async_scoped_session) -> None:
     iteration_start = datetime.now()
+    # TODO limit query to queues that do not have a "time_finished"
     queue_entries = await session.execute(select(Queue).where(Queue.time_next_check < iteration_start))
+    logger.debug("Daemon Iteration: %s", iteration_start)
 
     # TODO: should the daemon check any campaigns with a state == prepared that
     #       do not have queues? Queue creation should not be a manual step.
     queue_entry: Queue
+    processed_nodes = 0
     for (queue_entry,) in queue_entries:
-        queued_node = await queue_entry.get_node(session)
-        if (
-            queued_node.status.is_processable_script()
-            if isinstance(queued_node, Script)
-            else queued_node.status.is_processable_element()
-        ):
-            logger.info(f"Processing queue_entry {queued_node.fullname}")
-            await queue_entry.process_node(session)
-            sleep_time = await queue_entry.node_sleep_time(session)
-        else:
-            # Put this entry to sleep for a while
-            sleep_time = config.daemon.processing_interval
-        time_next_check = iteration_start + timedelta(seconds=sleep_time)
-        queue_entry.time_next_check = time_next_check
-        logger.info(f"Next check for {queued_node.fullname} at {time_next_check}")
+        try:
+            queued_node = await queue_entry.get_node(session)
+            if (
+                queued_node.status.is_processable_script()
+                if isinstance(queued_node, Script)
+                else queued_node.status.is_processable_element()
+            ):
+                logger.info("Processing queue_entry %s", queued_node.fullname)
+                await queue_entry.process_node(session)
+                processed_nodes += 1
+                sleep_time = await queue_entry.node_sleep_time(session)
+            else:
+                # Put this entry to sleep for a while
+                logger.debug("Not processing queue_entry %s", queued_node.fullname)
+                sleep_time = config.daemon.processing_interval
+            time_next_check = iteration_start + timedelta(seconds=sleep_time)
+            queue_entry.time_next_check = time_next_check
+            logger.info(f"Next check for {queued_node.fullname} at {time_next_check}")
+        except Exception:
+            logger.exception()
+            continue
     await session.commit()
+
+    # Try to allocate resources at the end of the loop, but do not crash if it
+    # doesn't work.
+    # FIXME this could be run async
+    try:
+        if config.daemon.allocate_resources and processed_nodes > 0:
+            allocate_resources()
+    except Exception:
+        logger.exception()
+
+
+def allocate_resources() -> None:
+    """Allocate resources for htcondor jobs submitted during the daemon
+    iteration.
+    """
+    if (htcondor := import_htcondor()) is None:
+        logger.warning("HTCondor is not available, not allocating resources")
+        return
+
+    coll = htcondor.Collector(config.htcondor.collector_host)
+
+    # Do we need to allocate resources? i.e., are there idle condor jobs for
+    # which we are responsible?
+
+    # FIXME we should round-robin submits to available schedds and approximate
+    # a global query for our idle jobs.
+
+    # schedds = coll.locateAll(htcondor.DaemonTypes.Schedd)
+
+    # Mapping of schedd ad to a list of its idle jobs
+    # idle_jobs = {
+    #     ad: htcondor.Schedd(ad).query(
+    #         projection=["ClusterId"],
+    #         constraint="(JobStatus == 1)",
+    #         opts=htcondor.QueryOpts.DefaultMyJobsOnly,
+    #     )
+    #     for ad in schedds
+    # }
+
+    # # Filter query result to those schedds with idle jobs
+    # idle_job_schedds = [k for k, v in idle_jobs.items() if v]
+
+    # if not idle_job_schedds:
+    #     return
+
+    # the schedd to which we need to submit this job should be one where idle
+    # jobs are available. Pick one per daemon iteration; if there are multiple
+    # schedds with idle jobs, the next loop will pick it up.
+    # schedd = htcondor.Schedd(idle_job_schedds.pop())
+
+    # FIXME only queries the single schedd to which we are submitting jobs
+    schedd_ad = coll.locate(htcondor.DaemonTypes.Schedd, name=config.htcondor.schedd_host)
+    schedd = htcondor.Schedd(schedd_ad)
+
+    idle_jobs = schedd.query(
+        projection=["ClusterId"],
+        constraint="(JobStatus == 1)",
+        opts=htcondor.QueryOpts.DefaultMyJobsOnly,
+    )
+    if not idle_jobs:
+        return
+
+    # Set the htcondor config in the submission environment
+    # The environment command in the submit file is a double-quoted,
+    # whitespace-delimited list of name=value pairs where literal quote marks
+    # are doubled ("" or '').
+    submission_environment = " ".join([f"{k}={v}" for k, v in build_htcondor_submit_environment().items()])
+
+    # The minimum necessary submission spec executes a resource allocation
+    # script to the local universe and does not preserve the output.
+    submission_spec = {
+        "executable": f"{config.htcondor.remote_user_home}/.local/bin/allocateNodes.py",
+        "arguments": (
+            f"--auto --account {config.slurm.account} -n 50 -m {config.slurm.duration} "
+            f"-q {config.slurm.partition} -g 240 {config.slurm.platform}"
+        ),
+        "environment": f'"{submission_environment}"',
+        "initialdir": config.htcondor.working_directory,
+        "batch_name": config.htcondor.batch_name,
+        "universe": "local",
+    }
+    submit_ad = htcondor.Submit(submission_spec)
+
+    # job cluster id of our resource allocation script; fire and forget
+    cluster_id = schedd.submit(submit_ad)
+    logger.info("Allocating Resources with condor job %s", cluster_id.cluster())
+    logger.debug(cluster_id)
diff --git a/src/lsst/cmservice/common/enums.py b/src/lsst/cmservice/common/enums.py
index c7ef7cdd3..e3214e321 100644
--- a/src/lsst/cmservice/common/enums.py
+++ b/src/lsst/cmservice/common/enums.py
@@ -248,7 +248,7 @@ class WmsMethodEnum(enum.Enum):
     panda = 1
         Runs under PanDA
 
-    ht_condor = 2
+    htcondor = 2
         Runs under HTCondor
 
     More methods to come...
@@ -257,4 +257,14 @@ class WmsMethodEnum(enum.Enum):
     default = -1
     bash = 0
     panda = 1
-    ht_condor = 2
+    htcondor = 2
+
+
+class WmsComputeSite(enum.Enum):
+    """Define a potential compute site"""
+
+    default = -1
+    usdf = 1
+    lanc = 2
+    ral = 3
+    in2p3 = 4
diff --git a/src/lsst/cmservice/common/errors.py b/src/lsst/cmservice/common/errors.py
index 7b0dcf9ef..a52489f88 100644
--- a/src/lsst/cmservice/common/errors.py
+++ b/src/lsst/cmservice/common/errors.py
@@ -51,7 +51,7 @@ class CMIDMismatchError(ValueError):
     """Raised when there is an ID mismatch between row IDs"""
 
 
-class CMIntegrityError(IntegrityError):  # pylint: disable=too-many-ancestors
+class CMIntegrityError(IntegrityError):
     """Raise when catching a sqlalchemy.exc.IntegrityError"""
 
 
diff --git a/src/lsst/cmservice/common/htcondor.py b/src/lsst/cmservice/common/htcondor.py
index cf2596f52..f80b13760 100644
--- a/src/lsst/cmservice/common/htcondor.py
+++ b/src/lsst/cmservice/common/htcondor.py
@@ -1,5 +1,10 @@
 """Utility functions for working with htcondor jobs"""
 
+import importlib.util
+import os
+import sys
+from collections.abc import Mapping
+from types import ModuleType
 from typing import Any
 
 from anyio import Path, open_process
@@ -8,6 +13,10 @@
 from ..config import config
 from .enums import StatusEnum
 from .errors import CMHTCondorCheckError, CMHTCondorSubmitError
+from .logging import LOGGER
+
+logger = LOGGER.bind(module=__name__)
+
 
 htcondor_status_map = {
     1: StatusEnum.running,
@@ -21,26 +30,26 @@
 
 
 async def write_htcondor_script(
-    htcondor_script_path: str | Path,
-    htcondor_log: str | Path,
-    script_url: str | Path,
-    log_url: str | Path,
+    htcondor_script_path: Path,
+    htcondor_log: Path,
+    script_url: Path,
+    log_url: Path,
     **kwargs: Any,
 ) -> Path:
     """Write a submit wrapper script for htcondor
 
     Parameters
     ----------
-    htcondor_script_path: str | anyio.Path
+    htcondor_script_path: anyio.Path
         Path for the wrapper file written by this function
 
-    htcondor_log: str | anyio.Path
+    htcondor_log: anyio.Path
         Path for the wrapper log
 
-    script_url: str | anyio.Path
+    script_url: anyio.Path
         Script to submit
 
-    log_url: str | anyio.Path
+    log_url: anyio.Path
         Location of job log file to write
 
     Returns
@@ -49,6 +58,8 @@ async def write_htcondor_script(
         Path to the log wrapper log
     """
     options = dict(
+        initialdir=config.htcondor.working_directory,
+        batch_name=config.htcondor.batch_name,
         should_transfer_files="Yes",
         when_to_transfer_output="ON_EXIT",
         get_env=True,
@@ -66,7 +77,7 @@ async def write_htcondor_script(
     ]
     for key, val in options.items():
         htcondor_script_contents.append(f"{key} = {val}")
-    htcondor_script_contents.append("queue")
+    htcondor_script_contents.append("queue\n")
 
     await Path(htcondor_script_path).write_text("\n".join(htcondor_script_contents))
     return Path(htcondor_log)
@@ -93,7 +104,8 @@ async def submit_htcondor_job(
 
     try:
         async with await open_process(
-            [config.htcondor.condor_submit_bin, htcondor_script_path]
+            [config.htcondor.condor_submit_bin, "-file", htcondor_script_path],
+            env=build_htcondor_submit_environment(),
         ) as condor_submit:
             if await condor_submit.wait() != 0:  # pragma: no cover
                 assert condor_submit.stderr
@@ -133,6 +145,7 @@ async def check_htcondor_job(
             raise CMHTCondorCheckError("No htcondor_id")
         async with await open_process(
             [config.htcondor.condor_q_bin, "-userlog", htcondor_id, "-af", "JobStatus", "ExitCode"],
+            env=build_htcondor_submit_environment(),
         ) as condor_q:  # pragma: no cover
             if await condor_q.wait() != 0:
                 assert condor_q.stderr
@@ -162,3 +175,70 @@ async def check_htcondor_job(
         else:
             status = StatusEnum.failed
     return status  # pragma: no cover
+
+
+def build_htcondor_submit_environment() -> Mapping[str, str]:
+    """Construct an environment to apply to the subprocess shell when
+    submitting an htcondor job.
+
+    The condor job will inherit this specific environment via the submit file
+    command `get_env = True`, so it must satisfy the requirements of any work
+    being performed in the submitted job.
+
+    This primarily means that if the job is to run a butler command, the
+    necessary environment variables to support butler must be present; if the
+    job is to run a bps command, the environment variables must support it.
+
+    This also means that the environment constructed here is fundamentally
+    different to the environment in which the service or daemon operates and
+    should closer match the environment of an interactive sdfianaXXX user at
+    SLAC.
+    """
+    # TODO use all configured htcondor config settings
+    # condor_environment = config.htcondor.model_dump(by_alias=True)
+    # TODO we should not always use the same schedd host. We could get a list
+    # of all schedds from the collector and pick one at random.
+    return dict(
+        CONDOR_CONFIG=config.htcondor.config_source,
+        _CONDOR_CONDOR_HOST=config.htcondor.collector_host,
+        _CONDOR_COLLECTOR_HOST=config.htcondor.collector_host,
+        _CONDOR_SCHEDD_HOST=config.htcondor.schedd_host,
+        _CONDOR_SEC_CLIENT_AUTHENTICATION_METHODS=config.htcondor.authn_methods,
+        _CONDOR_DAGMAN_MANAGER_JOB_APPEND_GETENV="True",
+        FS_REMOTE_DIR=config.htcondor.fs_remote_dir,
+        DAF_BUTLER_REPOSITORY_INDEX=config.butler.repository_index,
+        HOME=config.htcondor.remote_user_home,
+        LSST_VERSION=config.bps.lsst_version,
+        LSST_DISTRIB_DIR=config.bps.lsst_distrib_dir,
+        # FIX: because there is no db-auth.yaml in lsstsvc1's home directory
+        PGPASSFILE=f"{config.htcondor.remote_user_home}/.lsst/postgres-credentials.txt",
+        PGUSER=config.butler.default_username,
+        PATH=(
+            f"{config.htcondor.remote_user_home}/.local/bin:{config.htcondor.remote_user_home}/bin:{config.slurm.home}:"
+            f"/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin"
+        ),
+    )
+
+
+def import_htcondor() -> ModuleType | None:
+    """Import and return the htcondor module if it is available. Ensure the
+    the current configuration is loaded.
+    """
+    if (htcondor := sys.modules.get("htcondor")) is not None:
+        pass
+    elif (importlib.util.find_spec("htcondor")) is not None:
+        htcondor = importlib.import_module("htcondor")
+
+    if htcondor is None:
+        logger.warning("HTcondor not available.")
+        return None
+
+    # Ensure environment is configured for htcondor operations
+    # FIXME: the python process needs the correct condor env set up. Alternate
+    # to setting these values JIT in the os.environ would be to hack a way to
+    # have the config.htcondor submodel's validation_alias match the
+    # serialization_alias, e.g., "_CONDOR_value"
+    os.environ |= config.htcondor.model_dump(by_alias=True)
+    htcondor.reload_config()
+
+    return htcondor
diff --git a/src/lsst/cmservice/common/logging.py b/src/lsst/cmservice/common/logging.py
new file mode 100644
index 000000000..8769953b1
--- /dev/null
+++ b/src/lsst/cmservice/common/logging.py
@@ -0,0 +1,10 @@
+"""Provide a common application root logger."""
+
+import structlog
+from safir.logging import configure_logging
+
+from ..config import config
+
+configure_logging(profile=config.logging.profile, log_level=config.logging.level, name=config.logging.handle)
+
+LOGGER = structlog.get_logger(config.logging.handle)
diff --git a/src/lsst/cmservice/common/slurm.py b/src/lsst/cmservice/common/slurm.py
index 8b41d4479..cb1743c90 100644
--- a/src/lsst/cmservice/common/slurm.py
+++ b/src/lsst/cmservice/common/slurm.py
@@ -65,7 +65,7 @@ async def submit_slurm_job(
     try:
         async with await open_process(
             [
-                config.slurm.sbatch_bin,
+                f"{config.slurm.home}/sbatch",
                 "-o",
                 log_url,
                 "--mem",
@@ -119,7 +119,7 @@ async def check_slurm_job(
         return StatusEnum.running
     try:
         async with await open_process(
-            [config.slurm.sacct_bin, "--parsable", "-b", "-j", slurm_id]
+            [f"{config.slurm.home}/sacct", "--parsable", "-b", "-j", slurm_id]
         ) as slurm_check:  # pragma: no cover
             await slurm_check.wait()
             if slurm_check.returncode != 0:
diff --git a/src/lsst/cmservice/config.py b/src/lsst/cmservice/config.py
index d38f8a267..35fe078f2 100644
--- a/src/lsst/cmservice/config.py
+++ b/src/lsst/cmservice/config.py
@@ -4,7 +4,7 @@
 from pydantic import BaseModel, Field, field_validator
 from pydantic_settings import BaseSettings, SettingsConfigDict
 
-from .common.enums import ScriptMethodEnum, StatusEnum
+from .common.enums import ScriptMethodEnum, StatusEnum, WmsComputeSite
 
 __all__ = ["Configuration", "config"]
 
@@ -19,6 +19,16 @@ class BpsConfiguration(BaseModel):
     FIXME: rename to LsstConfiguration and consolidate multiple models?
     """
 
+    lsst_version: str = Field(
+        description="Default LSST version",
+        default="w_latest",
+    )
+
+    lsst_distrib_dir: str = Field(
+        description="Default distribution directory from which to setup lsst",
+        default="/sdf/group/rubin/sw",
+    )
+
     bps_bin: str = Field(
         description="Name of a bps client binary",
         default="bps",
@@ -51,6 +61,21 @@ class ButlerConfiguration(BaseModel):
         default="butler",
     )
 
+    repository_index: str = Field(
+        description="Fully qualified path to a butler repository index.",
+        default="/sdf/group/rubin/shared/data-repos.yaml",
+    )
+
+    authentication_file: str = Field(
+        description="Path and name of a db-auth.yaml to use with Butler",
+        default="~/.lsst/db-auth.yaml",
+    )
+
+    default_username: str = Field(
+        description="Default username to use for Butler registry authentication",
+        default="rubin",
+    )
+
     mock: bool = Field(
         description="Whether to mock out Butler calls.",
         default=False,
@@ -84,6 +109,25 @@ class HTCondorConfiguration(BaseModel):
     their serialization alias.
     """
 
+    config_source: str = Field(
+        description="Source of htcondor configuration",
+        default="ONLY_ENV",
+        serialization_alias="CONDOR_CONFIG",
+    )
+
+    remote_user_home: str = Field(
+        description=("Path to the user's home directory, as resolvable from an htcondor access node."),
+        default="/sdf/home/l/lsstsvc1",
+        exclude=True,
+    )
+
+    condor_home: str = Field(
+        description=("Path to the Condor home directory. Equivalent to the condor ``RELEASE_DIR`` macro."),
+        default="/opt/htcondor",
+        serialization_alias="_CONDOR_RELEASE_DIR",
+    )
+
+    # TODO retire these in favor of a path relative to condor_home
     condor_submit_bin: str = Field(
         description="Name of condor_submit client binary",
         default="condor_submit",
@@ -96,6 +140,33 @@ class HTCondorConfiguration(BaseModel):
         exclude=True,
     )
 
+    universe: str = Field(
+        description="HTCondor Universe into which a job will be submitted.",
+        default="vanilla",
+        serialization_alias="_CONDOR_DEFAULT_UNIVERSE",
+    )
+
+    working_directory: str = Field(
+        description=(
+            "Path to a working directory to use when submitting condor jobs. "
+            "This path must be available to both the submitting service and "
+            "the access point receiving the job. Corresponds to the "
+            "`initialdir` submit file command."
+        ),
+        default=".",
+        exclude=True,
+    )
+
+    batch_name: str = Field(
+        description=(
+            "Name to use in identifying condor jobs. Corresponds to "
+            "the `condor_submit` `-batch-name` parameter or submit file "
+            "`batch_name` command."
+        ),
+        default="usdf-cm-dev",
+        exclude=True,
+    )
+
     request_cpus: int = Field(
         description="Number of cores to request when submitting an htcondor job.",
         default=1,
@@ -117,26 +188,30 @@ class HTCondorConfiguration(BaseModel):
     collector_host: str = Field(
         description="Name of an htcondor collector host.",
         default="localhost",
-        serialization_alias="_condor_COLLECTOR_HOST",
+        serialization_alias="_CONDOR_COLLECTOR_HOST",
     )
 
     schedd_host: str = Field(
         description="Name of an htcondor schedd host.",
         default="localhost",
-        serialization_alias="_condor_SCHEDD_HOST",
+        serialization_alias="_CONDOR_SCHEDD_HOST",
     )
 
     authn_methods: str = Field(
         description="Secure client authentication methods, as comma-delimited strings",
-        default="FS,FS_REMOTE",
-        serialization_alias="_condor_SEC_CLIENT_AUTHENTICATION_METHODS",
+        default="FS_REMOTE",
+        serialization_alias="_CONDOR_SEC_CLIENT_AUTHENTICATION_METHODS",
     )
 
-    dagman_job_append_get_env: bool = Field(
-        description="...", default=True, serialization_alias="_condor_DAGMAN_MANAGER_JOB_APPEND_GETENV"
+    fs_remote_dir: str = Field(
+        description="Shared directory to use with htcondor remote filesystem authentication.",
+        default="/tmp",
+        serialization_alias="FS_REMOTE_DIR",
     )
 
 
+# TODO deprecate and remove "slurm"-specific logic from cm-service; it is
+#      unlikely that interfacing with slurm directly from k8s will be possible.
 class SlurmConfiguration(BaseModel):
     """Configuration settings for slurm client operations.
 
@@ -146,16 +221,14 @@ class SlurmConfiguration(BaseModel):
     ----
     Default SBATCH_* variables could work just as well, but it is useful to
     have this as a document of what settings are actually used.
-    """
 
-    sacct_bin: str = Field(
-        description="Name of sacct slurm client binary",
-        default="sacct",
-    )
+    These settings should also apply to htcondor resource allocation jobs
+    that are equivalent to "allocateNodes"
+    """
 
-    sbatch_bin: str = Field(
-        description="Name of sbatch slurm client binary",
-        default="sbatch",
+    home: str = Field(
+        description="Location of the installed slurm client binaries",
+        default="/opt/slurm/slurm-curr/bin",
     )
 
     memory: str = Field(
@@ -173,6 +246,16 @@ class SlurmConfiguration(BaseModel):
         default="milano",
     )
 
+    platform: str = Field(
+        description="Platform requested when submitting a slurm job.",
+        default="s3df",
+    )
+
+    duration: str = Field(
+        description="Expected Duration for a cmservice script that needs to be scheduled.",
+        default="0-1:0:0",
+    )
+
 
 class AsgiConfiguration(BaseModel):
     """Configuration for the application's ASGI web server."""
@@ -194,7 +277,7 @@ class AsgiConfiguration(BaseModel):
 
     prefix: str = Field(
         description="The URL prefix for the cm-service API",
-        default="/cmservice",
+        default="/cm-service",
     )
 
     frontend_prefix: str = Field(
@@ -211,6 +294,11 @@ class AsgiConfiguration(BaseModel):
 class LoggingConfiguration(BaseModel):
     """Configuration for the application's logging facility."""
 
+    handle: str = Field(
+        default="cm-service",
+        title="Handle or name of the root logger",
+    )
+
     level: str = Field(
         default="INFO",
         title="Log level of the application's logger",
@@ -228,6 +316,11 @@ class DaemonConfiguration(BaseModel):
     Set according to DAEMON__FIELD environment variables.
     """
 
+    allocate_resources: bool = Field(
+        default=False,
+        description="Whether the daemon should try to allocate its own htcondor or slurm resources.",
+    )
+
     processing_interval: int = Field(
         default=30,
         description=(
@@ -297,6 +390,11 @@ class Configuration(BaseSettings):
         default=ScriptMethodEnum.htcondor,
     )
 
+    compute_site: WmsComputeSite = Field(
+        description="The default WMS compute site",
+        default=WmsComputeSite.usdf,
+    )
+
     mock_status: StatusEnum | None = Field(
         description="A fake status to return from all operations",
         default=None,
@@ -313,6 +411,7 @@ def validate_mock_status_by_name(cls, value: str | StatusEnum) -> StatusEnum | N
             warn(f"Invalid mock status ({value}) provided to config, using default.")
             return None
 
+    # TODO refactor these identical field validators with type generics
     @field_validator("script_handler", mode="before")
     @classmethod
     def validate_script_method_by_name(cls, value: str | ScriptMethodEnum) -> ScriptMethodEnum:
@@ -327,6 +426,20 @@ def validate_script_method_by_name(cls, value: str | ScriptMethodEnum) -> Script
             warn(f"Invalid script handler ({value}) provided to config, using default.")
             return ScriptMethodEnum.htcondor
 
+    @field_validator("compute_site", mode="before")
+    @classmethod
+    def validate_compute_site_by_name(cls, value: str | WmsComputeSite) -> WmsComputeSite:
+        """Use a string value to resolve an enum by its name, falling back to
+        the default value if an invalid input is provided.
+        """
+        if isinstance(value, WmsComputeSite):
+            return value
+        try:
+            return WmsComputeSite[value]
+        except KeyError:
+            warn(f"Invalid script handler ({value}) provided to config, using default.")
+            return WmsComputeSite.usdf
+
 
 config = Configuration()
 """Configuration for cm-service."""
diff --git a/src/lsst/cmservice/daemon.py b/src/lsst/cmservice/daemon.py
index 4e415a559..e760e29f7 100644
--- a/src/lsst/cmservice/daemon.py
+++ b/src/lsst/cmservice/daemon.py
@@ -2,20 +2,21 @@
 from collections.abc import AsyncGenerator
 from contextlib import asynccontextmanager
 
-import structlog
 import uvicorn
 from anyio import current_time, sleep_until
 from fastapi import FastAPI
 from safir.database import create_async_session, create_database_engine
-from safir.logging import configure_logging, configure_uvicorn_logging
+from safir.logging import configure_uvicorn_logging
 
 from . import __version__
 from .common.daemon import daemon_iteration
+from .common.logging import LOGGER
 from .config import config
 from .routers.healthz import health_router
 
 configure_uvicorn_logging(config.logging.level)
-configure_logging(profile=config.logging.profile, log_level=config.logging.level, name=__name__)
+
+logger = LOGGER.bind(module=__name__)
 
 
 @asynccontextmanager
@@ -34,7 +35,6 @@ async def main_loop() -> None:
     With a database session, perform a single daemon interation and then sleep
     until the next daemon appointment.
     """
-    logger = structlog.get_logger(__name__)
     engine = create_database_engine(config.db.url, config.db.password)
     sleep_time = config.daemon.processing_interval
 
diff --git a/src/lsst/cmservice/db/group.py b/src/lsst/cmservice/db/group.py
index 6c18fb9f7..3f3a690b4 100644
--- a/src/lsst/cmservice/db/group.py
+++ b/src/lsst/cmservice/db/group.py
@@ -100,7 +100,7 @@ def __repr__(self) -> str:
 
     async def children(
         self,
-        session: async_scoped_session,  # pylint: disable=unused-argument
+        session: async_scoped_session,
     ) -> Iterable:
         """Maps self.g_ to self.children() for consistency"""
         await session.refresh(self, attribute_names=["jobs_"])
diff --git a/src/lsst/cmservice/db/handler.py b/src/lsst/cmservice/db/handler.py
index 421b7b6a8..6e0f01536 100644
--- a/src/lsst/cmservice/db/handler.py
+++ b/src/lsst/cmservice/db/handler.py
@@ -10,6 +10,7 @@
 
 from ..common.enums import StatusEnum
 from ..common.errors import CMBadHandlerTypeError
+from ..common.logging import LOGGER
 from ..common.utils import add_sys_path
 
 if TYPE_CHECKING:
@@ -17,6 +18,8 @@
     from .node import NodeMixin
     from .script import Script
 
+logger = LOGGER.bind(module=__name__)
+
 
 class Handler:
     """Base class to handle callbacks generated by particular
diff --git a/src/lsst/cmservice/db/node.py b/src/lsst/cmservice/db/node.py
index d96186000..2948c097d 100644
--- a/src/lsst/cmservice/db/node.py
+++ b/src/lsst/cmservice/db/node.py
@@ -15,6 +15,7 @@
     CMResolveCollectionsError,
     test_type_and_raise,
 )
+from ..common.logging import LOGGER
 from ..config import config
 from .handler import Handler
 from .row import RowMixin
@@ -25,6 +26,8 @@
     from .campaign import Campaign
     from .element import ElementMixin
 
+logger = LOGGER.bind(module=__name__)
+
 
 class NodeMixin(RowMixin):
     """Mixin class to define common features of database rows
@@ -608,7 +611,7 @@ async def check_prerequisites(
         """
         try:
             await session.refresh(self, attribute_names=["prereqs_"])
-        except Exception:  # pylint: disable=broad-exception-caught
+        except Exception:
             return True
         for prereq_ in self.prereqs_:
             is_done = await prereq_.is_done(session)
@@ -688,7 +691,7 @@ async def reset(
         await self.update_values(session, status=StatusEnum.waiting, superseded=False)
         return self
 
-    async def _clean_up_node(  # pylint: disable=unused-argument
+    async def _clean_up_node(
         self,
         session: async_scoped_session,
         *,
@@ -734,6 +737,7 @@ async def process(
             Status of the processing
         """
         handler = await self.get_handler(session)
+        logger.debug("Processing node with handler %s", handler.get_handler_class_name())
         return await handler.process(session, self, **kwargs)
 
     async def run_check(
diff --git a/src/lsst/cmservice/db/queue.py b/src/lsst/cmservice/db/queue.py
index 3df8149bb..b7f09db60 100644
--- a/src/lsst/cmservice/db/queue.py
+++ b/src/lsst/cmservice/db/queue.py
@@ -10,6 +10,7 @@
 
 from ..common.enums import LevelEnum
 from ..common.errors import CMBadEnumError, CMMissingFullnameError
+from ..common.logging import LOGGER
 from .base import Base
 from .campaign import Campaign
 from .group import Group
@@ -18,6 +19,8 @@
 from .script import Script
 from .step import Step
 
+logger = LOGGER.bind(module=__name__)
+
 
 class Queue(Base, NodeMixin):
     """Database table to implement processing queue"""
@@ -214,9 +217,11 @@ async def process_node(
         node = await self.get_node(session)
 
         if node.level == LevelEnum.script:
+            logger.debug("Processing a %s", node.level)
             if not node.status.is_processable_script():
                 return False
         if not node.status.is_processable_element():
+            logger.debug("Node %s is not processable", node.name)
             return False
 
         process_kwargs: dict = {}
diff --git a/src/lsst/cmservice/db/row.py b/src/lsst/cmservice/db/row.py
index d8a62b933..df4b25286 100644
--- a/src/lsst/cmservice/db/row.py
+++ b/src/lsst/cmservice/db/row.py
@@ -216,7 +216,7 @@ async def delete_row(
         await cls._delete_hook(session, row_id)
 
     @classmethod
-    async def _delete_hook(  # pylint: disable=unused-argument
+    async def _delete_hook(
         cls,
         session: async_scoped_session,
         row_id: int,
@@ -332,7 +332,7 @@ async def create_row(
     @classmethod
     async def get_create_kwargs(
         cls: type[T],
-        session: async_scoped_session,  # pylint: disable=unused-argument
+        session: async_scoped_session,
         **kwargs: Any,
     ) -> dict:
         """Get additional keywords needed to create a row
diff --git a/src/lsst/cmservice/db/script.py b/src/lsst/cmservice/db/script.py
index 1b9e99611..f89fb4f0e 100644
--- a/src/lsst/cmservice/db/script.py
+++ b/src/lsst/cmservice/db/script.py
@@ -9,6 +9,7 @@
 
 from ..common.enums import LevelEnum, NodeTypeEnum, ScriptMethodEnum, StatusEnum
 from ..common.errors import CMBadEnumError, CMMissingRowCreateInputError
+from ..config import config
 from .base import Base
 from .campaign import Campaign
 from .element import ElementMixin
@@ -89,6 +90,16 @@ class Script(Base, NodeMixin):
         "superseded",
     ]
 
+    @property
+    def run_method(self) -> ScriptMethodEnum:
+        """Get a ``ScriptMethodEnum`` for the script, resolving the default
+        method as necessary.
+        """
+        if self.method is ScriptMethodEnum.default:
+            return config.script_handler
+        else:
+            return self.method
+
     @property
     def level(self) -> LevelEnum:
         """Returns LevelEnum.script"""
diff --git a/src/lsst/cmservice/db/script_template.py b/src/lsst/cmservice/db/script_template.py
index a3ff53384..c5d5de241 100644
--- a/src/lsst/cmservice/db/script_template.py
+++ b/src/lsst/cmservice/db/script_template.py
@@ -55,7 +55,7 @@ async def get_create_kwargs(
         }
 
     @classmethod
-    async def load(  # pylint: disable=too-many-arguments
+    async def load(
         cls,
         session: async_scoped_session,
         name: str,
diff --git a/src/lsst/cmservice/handlers/element_handler.py b/src/lsst/cmservice/handlers/element_handler.py
index 3c3cacb11..a75b539a5 100644
--- a/src/lsst/cmservice/handlers/element_handler.py
+++ b/src/lsst/cmservice/handlers/element_handler.py
@@ -224,7 +224,7 @@ async def continue_processing(
         await element.update_values(session, status=StatusEnum.running)
         return (changed, StatusEnum.running)
 
-    async def review(  # pylint: disable=unused-argument
+    async def review(
         self,
         session: async_scoped_session,
         element: ElementMixin,
@@ -401,7 +401,7 @@ async def check(
         await element.update_values(session, status=status)
         return (True, status)
 
-    async def _post_check(  # pylint: disable=unused-argument
+    async def _post_check(
         self,
         session: async_scoped_session,
         element: ElementMixin,
diff --git a/src/lsst/cmservice/handlers/elements.py b/src/lsst/cmservice/handlers/elements.py
index 3c07ba92c..8b30c9da8 100644
--- a/src/lsst/cmservice/handlers/elements.py
+++ b/src/lsst/cmservice/handlers/elements.py
@@ -10,6 +10,7 @@
 
 from lsst.daf.butler import Butler
 
+from ..common.butler import get_butler_config
 from ..common.enums import StatusEnum
 from ..common.errors import CMMissingScriptInputError, test_type_and_raise
 from ..config import config
@@ -126,7 +127,7 @@ class Splitter:
     """Class to split Steps into Groups"""
 
     @classmethod
-    async def split(  # pylint: disable=unused-argument
+    async def split(
         cls,
         session: async_scoped_session,
         script: Script,
@@ -220,9 +221,10 @@ async def split(
         if mock_butler:
             sorted_field_values = np.arange(10)
         else:
+            butler_config = await get_butler_config(butler_repo, without_datastore=True)
             butler_f = partial(
                 Butler.from_config,
-                butler_repo,
+                butler_config,
                 collections=[input_coll, campaign_input_coll],
                 without_datastore=True,
             )
diff --git a/src/lsst/cmservice/handlers/interface.py b/src/lsst/cmservice/handlers/interface.py
index 3b02edc28..360c4b1d9 100644
--- a/src/lsst/cmservice/handlers/interface.py
+++ b/src/lsst/cmservice/handlers/interface.py
@@ -531,7 +531,7 @@ async def load_specification(
     return result
 
 
-async def load_and_create_campaign(  # pylint: disable=too-many-arguments
+async def load_and_create_campaign(
     session: async_scoped_session,
     yaml_file: str,
     parent_name: str,
@@ -677,7 +677,7 @@ async def load_manifest_report(
     return result
 
 
-async def match_pipetask_errors(  # pylint: disable=unused-argument
+async def match_pipetask_errors(
     session: async_scoped_session,
     *,
     rematch: bool = False,
diff --git a/src/lsst/cmservice/handlers/jobs.py b/src/lsst/cmservice/handlers/jobs.py
index 446b32be4..bc3b22d06 100644
--- a/src/lsst/cmservice/handlers/jobs.py
+++ b/src/lsst/cmservice/handlers/jobs.py
@@ -8,6 +8,7 @@
 import yaml
 from anyio import Path
 from fastapi.concurrency import run_in_threadpool
+from jinja2 import Environment, PackageLoader
 from sqlalchemy.ext.asyncio import async_scoped_session
 
 from lsst.ctrl.bps import BaseWmsService, WmsStates
@@ -23,6 +24,7 @@
     CMMissingScriptInputError,
     test_type_and_raise,
 )
+from ..common.logging import LOGGER
 from ..config import config
 from ..db.element import ElementMixin
 from ..db.job import Job
@@ -46,6 +48,8 @@
     WmsStates.PRUNED: TaskStatusEnum.failed,
 }
 
+logger = LOGGER.bind(module=__name__)
+
 
 class BpsScriptHandler(ScriptHandler):
     """Write a script to run bps jobs
@@ -54,6 +58,8 @@ class BpsScriptHandler(ScriptHandler):
     `parent.collections['run']`
     """
 
+    wms_method = WmsMethodEnum.default
+
     async def _write_script(
         self,
         session: async_scoped_session,
@@ -61,9 +67,13 @@ async def _write_script(
         parent: ElementMixin,
         **kwargs: Any,
     ) -> StatusEnum:
-        specification = await script.get_specification(session)
-        resolved_cols = await script.resolve_collections(session)
+        # Database operations
+        await session.refresh(parent, attribute_names=["c_", "p_"])
         data_dict = await script.data_dict(session)
+        resolved_cols = await script.resolve_collections(session)
+
+        # Resolve mandatory data element inputs. All of these values must be
+        # provided somewhere along the SpecBlock chain.
         try:
             prod_area = os.path.expandvars(data_dict["prod_area"])
             butler_repo = os.path.expandvars(data_dict["butler_repo"])
@@ -72,23 +82,22 @@ async def _write_script(
             pipeline_yaml = os.path.expandvars(data_dict["pipeline_yaml"])
             run_coll = resolved_cols["run"]
             input_colls = resolved_cols["inputs"]
-            bps_core_yaml_template = data_dict["bps_core_yaml_template"]
-            bps_core_script_template = data_dict["bps_core_script_template"]
-            bps_wms_script_template = data_dict["bps_wms_script_template"]
         except KeyError as msg:
             raise CMMissingScriptInputError(f"{script.fullname} missing an input: {msg}") from msg
 
-        # optional stuff from data_dict
-        rescue = data_dict.get("rescue", False)
-        skip_colls = data_dict.get("skip_colls", "")
-        custom_lsst_setup = data_dict.get("custom_lsst_setup", None)
-        bps_wms_yaml_file = data_dict.get("bps_wms_yaml_file", None)
-        bps_wms_clustering_file = data_dict.get("bps_wms_clustering_file", None)
-        bps_wms_resources_file = data_dict.get("bps_wms_resources_file", None)
-        bps_wms_extra_files = data_dict.get("bps_wms_extra_files", [])
-        bps_extra_config = data_dict.get("bps_extra_config", None)
-        data_query = data_dict.get("data_query", None)
-        extra_qgraph_options = data_dict.get("extra_qgraph_options", None)
+        # workflow_config is the values dictionary to use while rendering a
+        # yaml template, NOT the yaml template itself!
+        workflow_config: dict[str, Any] = {}
+        workflow_config["project"] = parent.p_.name  # type: ignore
+        workflow_config["campaign"] = parent.c_.name  # type: ignore
+        workflow_config["pipeline_yaml"] = pipeline_yaml
+        workflow_config["lsst_version"] = lsst_version
+        workflow_config["lsst_distrib_dir"] = lsst_distrib_dir
+        workflow_config["wms"] = self.wms_method.name
+        workflow_config["script_method"] = script.run_method.name
+        workflow_config["compute_site"] = data_dict.get("compute_site", self.default_compute_site.name)
+        workflow_config["custom_lsst_setup"] = data_dict.get("custom_lsst_setup", None)
+        workflow_config["extra_qgraph_options"] = data_dict.get("extra_qgraph_options", None)
 
         # Get the output file paths
         script_url = await self._set_script_files(session, script, prod_area)
@@ -97,71 +106,62 @@ async def _write_script(
             os.path.expandvars(f"{prod_area}/{script.fullname}_bps_config.yaml")
         ).resolve()
         log_url = await Path(os.path.expandvars(f"{prod_area}/{script.fullname}.log")).resolve()
-
-        # get the requested templates
-        bps_core_script_template_ = await specification.get_script_template(
-            session,
-            bps_core_script_template,
-        )
-        bps_core_yaml_template_ = await specification.get_script_template(
-            session,
-            bps_core_yaml_template,
-        )
-        bps_wms_script_template_ = await specification.get_script_template(
-            session,
-            bps_wms_script_template,
-        )
-
         config_path = await Path(config_url).resolve()
         submit_path = await Path(f"{prod_area}/{parent.fullname}/submit").resolve()
+        workflow_config["submit_path"] = str(submit_path)
+
         try:
             await run_in_threadpool(shutil.rmtree, submit_path)
         except FileNotFoundError:
             pass
 
-        # build up the bps wrapper script
-        command = (
-            f"{config.bps.bps_bin} --log-file {json_url} --no-log-tty submit " f"{config_path} > {log_url}"
-        )
-
-        prepend = bps_core_script_template_.data["text"].replace("{lsst_version}", lsst_version)  # type: ignore
-        prepend = prepend.replace("{lsst_distrib_dir}", lsst_distrib_dir)
-        # Add custom_lsst_setup to the bps submit script
-        # in case it is a change to bps itself
-        if custom_lsst_setup:  # pragma: no cover
-            prepend += f"\n{custom_lsst_setup}\n"
-        prepend += bps_wms_script_template_.data["text"]  # type: ignore
-
-        await write_bash_script(script_url, command, prepend=prepend)
+        command = f"{config.bps.bps_bin} --log-file {json_url} --no-log-tty submit {config_path} > {log_url}"
+        await write_bash_script(script_url, command, values=workflow_config)
 
-        workflow_config = bps_core_yaml_template_.data.copy()  # type: ignore
+        # FIXME at this point, how could the following path *not* exist?
+        #       is this meant to be `config_url` instead?
+        await Path(script_url).parent.mkdir(parents=True, exist_ok=True)
 
+        workflow_config["extra_yaml_literals"] = []
         include_configs = []
-        for to_include_ in [bps_wms_yaml_file, bps_wms_clustering_file, bps_wms_resources_file]:
+
+        # FIXME `bps_wms_*_file` should be added to the generic list of
+        # `bps_wms_extra_files` instead of being specific keywords. The only
+        # reason they are kept separate is to support overrides of their
+        # specific role
+        bps_wms_extra_files = data_dict.get("bps_wms_extra_files", [])
+        bps_wms_clustering_file = data_dict.get("bps_wms_clustering_file", None)
+        bps_wms_resources_file = data_dict.get("bps_wms_resources_file", None)
+        bps_wms_yaml_file = data_dict.get("bps_wms_yaml_file", None)
+        for to_include_ in [
+            bps_wms_yaml_file,
+            bps_wms_clustering_file,
+            bps_wms_resources_file,
+            *bps_wms_extra_files,
+        ]:
             if to_include_:
                 # We want abspaths, but we need to be careful about
                 # envvars that are not yet expanded
                 to_include_ = os.path.expandvars(to_include_)
-                if "$" not in to_include_:
-                    to_include_ = await Path(to_include_).resolve()
-                include_configs.append(str(to_include_))
-        include_configs += bps_wms_extra_files
-
-        workflow_config["includeConfigs"] = include_configs  # type: ignore
-
-        await session.refresh(parent, attribute_names=["c_", "p_"])
-        workflow_config["project"] = parent.p_.name  # type: ignore
-        workflow_config["campaign"] = parent.c_.name  # type: ignore
-
-        workflow_config["submitPath"] = str(submit_path)  # type: ignore
-
-        workflow_config["LSST_VERSION"] = os.path.expandvars(lsst_version)  # type: ignore
-        if custom_lsst_setup:  # pragma: no cover
-            workflow_config["custom_lsst_setup"] = custom_lsst_setup  # type: ignore
-        workflow_config["pipelineYaml"] = pipeline_yaml  # type: ignore
-
-        if extra_qgraph_options:  # pragma: no cover
-            workflow_config["extraQgraphOptions"] = extra_qgraph_options.replace("\n", " ").strip()  # type: ignore
+                # If the potential include file has an unexpanded env var, we
+                # delegate that expansion to the bps runtime, since it may
+                # refer to a stack env var we do not understand.
+                if "$" in to_include_:
+                    include_configs.append(str(to_include_))
+                    continue
+
+                # Otherwise, instead of including it we should render it out
+                # because it's a path we understand but the bps runtime won't
+                to_include_ = await Path(to_include_).resolve()
+
+                try:
+                    include_yaml_ = yaml.dump(yaml.safe_load(await to_include_.read_text()))
+                    workflow_config["extra_yaml_literals"].append(include_yaml_)
+                except yaml.YAMLError:
+                    logger.exception()
+                    raise
+
+        workflow_config["include_configs"] = include_configs
 
         if isinstance(input_colls, list):  # pragma: no cover
             in_collection = ",".join(input_colls)
@@ -169,25 +169,24 @@ async def _write_script(
             in_collection = input_colls
 
         payload = {
-            "payloadName": parent.c_.name,  # type: ignore
-            "butlerConfig": butler_repo,
-            "outputRun": run_coll,
-            "inCollection": in_collection,
+            "name": parent.c_.name,  # type: ignore
+            "butler_config": butler_repo,
+            "output_run_collection": run_coll,
+            "input_collection": in_collection,
+            "data_query": data_dict.get("data_query", None),
         }
-        if data_query:
-            payload["dataQuery"] = data_query.replace("\n", " ").strip()
-        if rescue:  # pragma: no cover
+        if data_dict.get("rescue", False):  # pragma: no cover
+            skip_colls = data_dict.get("skip_colls", "")
             payload["extra_args"] = f"--skip-existing-in {skip_colls}"
 
-        workflow_config["payload"] = payload  # type: ignore
-
-        if bps_extra_config:  # pragma: no cover
-            workflow_config.update(**bps_extra_config)  # type: ignore
-
-        await Path(script_url).parent.mkdir(parents=True, exist_ok=True)
+        workflow_config["payload"] = payload
 
+        # Get the yaml template using package lookup
+        config_template_environment = Environment(loader=PackageLoader("lsst.cmservice"))
+        config_template = config_template_environment.get_template("bps_submit_yaml.j2")
         try:
-            yaml_output = yaml.dump(workflow_config)
+            # Render bps_submit_yaml template to `config_url`
+            yaml_output = config_template.render(workflow_config)
             await Path(config_url).write_text(yaml_output)
         except yaml.YAMLError as yaml_error:
             raise yaml.YAMLError(f"Error writing a script to run BPS job {script}; threw {yaml_error}")
@@ -435,7 +434,7 @@ def get_job_id(cls, bps_dict: dict) -> str:
 class HTCondorScriptHandler(BpsScriptHandler):
     """Class to handle running Bps for ht_condor jobs"""
 
-    wms_method = WmsMethodEnum.ht_condor
+    wms_method = WmsMethodEnum.htcondor
 
     @classmethod
     def get_job_id(cls, bps_dict: dict) -> str:
@@ -464,37 +463,26 @@ async def _write_script(
         parent: ElementMixin,
         **kwargs: Any,
     ) -> StatusEnum:
-        specification = await script.get_specification(session)
         resolved_cols = await script.resolve_collections(session)
         data_dict = await script.data_dict(session)
         prod_area = os.path.expandvars(data_dict["prod_area"])
         script_url = await self._set_script_files(session, script, prod_area)
         butler_repo = data_dict["butler_repo"]
-        lsst_distrib_dir = data_dict["lsst_distrib_dir"]
-        lsst_version = data_dict["lsst_version"]
         job_run_coll = resolved_cols["job_run"]
         qgraph_file = f"{job_run_coll}.qgraph".replace("/", "_")
 
         graph_url = await Path(f"{prod_area}/{parent.fullname}/submit/{qgraph_file}").resolve()
         report_url = await Path(f"{prod_area}/{parent.fullname}/submit/manifest_report.yaml").resolve()
 
-        manifest_script_template = await specification.get_script_template(
-            session,
-            data_dict["manifest_script_template"],
-        )
-        prepend = manifest_script_template.data["text"].replace("{lsst_version}", lsst_version)  # type: ignore
-        prepend = prepend.replace("{lsst_distrib_dir}", lsst_distrib_dir)
-        if "custom_lsst_setup" in data_dict:  # pragma: no cover
-            custom_lsst_setup = data_dict["custom_lsst_setup"]
-            prepend += f"\n{custom_lsst_setup}"
-
-        # Strip leading/trailing spaces just in case
-        prepend = "\n".join([line.strip() for line in prepend.splitlines()])
+        template_values = {
+            "script_method": script.run_method.name,
+            **data_dict,
+        }
 
         command = (
             f"{config.bps.pipetask_bin} report --full-output-filename {report_url} {butler_repo} {graph_url}"
         )
-        await write_bash_script(script_url, command, prepend=prepend)
+        await write_bash_script(script_url, command, values=template_values)
 
         return StatusEnum.prepared
 
diff --git a/src/lsst/cmservice/handlers/script_handler.py b/src/lsst/cmservice/handlers/script_handler.py
index 8dd8ef690..f6e146f00 100644
--- a/src/lsst/cmservice/handlers/script_handler.py
+++ b/src/lsst/cmservice/handlers/script_handler.py
@@ -217,7 +217,7 @@ async def check(
         """
         raise NotImplementedError("{type(self)}.check()")
 
-    async def review_script(  # pylint: disable=unused-argument
+    async def review_script(
         self,
         session: async_scoped_session,
         script: Script,
@@ -309,9 +309,10 @@ class ScriptHandler(BaseScriptHandler):
     """SubClass of Handler to deal with script operations using real scripts"""
 
     default_method = config.script_handler
+    default_compute_site = config.compute_site
 
     @staticmethod
-    async def _check_stamp_file(  # pylint: disable=unused-argument
+    async def _check_stamp_file(
         session: async_scoped_session,
         stamp_file: str | None,
         script: Script,
@@ -348,7 +349,7 @@ async def _check_stamp_file(  # pylint: disable=unused-argument
         await script.update_values(session, status=status)
         return status
 
-    async def _check_slurm_job(  # pylint: disable=unused-argument
+    async def _check_slurm_job(
         self,
         session: async_scoped_session,
         slurm_id: str | None,
@@ -384,7 +385,7 @@ async def _check_slurm_job(  # pylint: disable=unused-argument
         await script.update_values(session, status=status)
         return status
 
-    async def _check_htcondor_job(  # pylint: disable=unused-argument
+    async def _check_htcondor_job(
         self,
         session: async_scoped_session,
         htcondor_id: str | None,
@@ -437,7 +438,7 @@ async def prepare(
         elif script_method == ScriptMethodEnum.slurm:
             status = await self._write_script(session, script, parent, **kwargs)
         elif script_method == ScriptMethodEnum.htcondor:
-            status = await self._write_script(session, script, parent, **kwargs)
+            status = await self._write_script(session, script, parent, setup_stack=True, **kwargs)
         else:  # pragma: no cover
             raise CMBadExecutionMethodError(f"Bad script method {script_method}")
         await script.update_values(session, status=status)
@@ -653,7 +654,7 @@ async def check(
         await script.update_values(session, status=status)
         return status
 
-    async def _do_prepare(  # pylint: disable=unused-argument
+    async def _do_prepare(
         self,
         session: async_scoped_session,
         script: Script,
@@ -680,7 +681,7 @@ async def _do_prepare(  # pylint: disable=unused-argument
         """
         raise NotImplementedError
 
-    async def _do_run(  # pylint: disable=unused-argument
+    async def _do_run(
         self,
         session: async_scoped_session,
         script: Script,
@@ -707,7 +708,7 @@ async def _do_run(  # pylint: disable=unused-argument
         """
         return StatusEnum.running
 
-    async def _do_check(  # pylint: disable=unused-argument
+    async def _do_check(
         self,
         session: async_scoped_session,
         script: Script,
diff --git a/src/lsst/cmservice/handlers/scripts.py b/src/lsst/cmservice/handlers/scripts.py
index f15f37252..4f9a518b5 100644
--- a/src/lsst/cmservice/handlers/scripts.py
+++ b/src/lsst/cmservice/handlers/scripts.py
@@ -14,20 +14,21 @@
     remove_non_run_collections,
     remove_run_collections,
 )
-from ..common.enums import LevelEnum, ScriptMethodEnum, StatusEnum
+from ..common.enums import LevelEnum, StatusEnum
 from ..common.errors import CMBadExecutionMethodError, CMMissingScriptInputError, test_type_and_raise
+from ..common.logging import LOGGER
 from ..config import config
 from ..db.element import ElementMixin
 from ..db.script import Script
 from ..db.step import Step
 from .script_handler import ScriptHandler
 
+logger = LOGGER.bind(module=__name__)
+
 
 class NullScriptHandler(ScriptHandler):
     """A no-op script, mostly for testing"""
 
-    default_method = ScriptMethodEnum.bash
-
     async def _write_script(
         self,
         session: async_scoped_session,
@@ -44,8 +45,14 @@ async def _write_script(
         except KeyError as e:
             raise CMMissingScriptInputError(f"{script.fullname} missing an input: {e}") from e
 
+        template_values = {
+            "script_method": script.run_method.name,
+            **data_dict,
+        }
+
         command = f"echo trivial {butler_repo} {output_coll}"
-        await write_bash_script(script_url, command, prepend="#!/usr/bin/env bash\n", **data_dict)
+
+        await write_bash_script(script_url, command, values=template_values)
         await script.update_values(session, script_url=script_url, status=StatusEnum.prepared)
         return StatusEnum.prepared
 
@@ -97,7 +104,13 @@ async def _write_script(
                 command += f" {input_coll}"
         else:
             command += f" {input_colls}"
-        await write_bash_script(script_url, command, prepend="#!/usr/bin/env bash\n", **data_dict)
+
+        template_values = {
+            "script_method": script.run_method.name,
+            **data_dict,
+        }
+
+        await write_bash_script(script_url, command, values=template_values)
         await script.update_values(session, script_url=script_url, status=StatusEnum.prepared)
         return StatusEnum.prepared
 
@@ -152,7 +165,13 @@ async def _write_script(
             f"{config.butler.butler_bin} collection-chain "
             f"{butler_repo} {output_coll} --mode prepend {input_coll}"
         )
-        await write_bash_script(script_url, command, prepend="#!/usr/bin/env bash\n", **data_dict)
+
+        template_values = {
+            "script_method": script.run_method.name,
+            **data_dict,
+        }
+
+        await write_bash_script(script_url, command, values=template_values)
         await script.update_values(session, script_url=script_url, status=StatusEnum.prepared)
         return StatusEnum.prepared
 
@@ -225,7 +244,13 @@ async def _write_script(
             command += f" {collect_coll_}"
         for input_coll_ in input_colls:
             command += f" {input_coll_}"
-        await write_bash_script(script_url, command, prepend="#!/usr/bin/env bash\n", **data_dict)
+
+        template_values = {
+            "script_method": script.run_method.name,
+            **data_dict,
+        }
+
+        await write_bash_script(script_url, command, values=template_values)
         await script.update_values(session, script_url=script_url, status=StatusEnum.prepared)
         return StatusEnum.prepared
 
@@ -280,7 +305,13 @@ async def _write_script(
         command = f"{config.butler.butler_bin} associate {butler_repo} {output_coll}"
         command += f" --collections {input_coll}"
         command += f' --where "{data_query}"' if data_query else ""
-        await write_bash_script(script_url, command, prepend="#!/usr/bin/env bash\n", **data_dict)
+
+        template_values = {
+            "script_method": script.run_method.name,
+            **data_dict,
+        }
+
+        await write_bash_script(script_url, command, values=template_values)
         await script.update_values(session, script_url=script_url, status=StatusEnum.prepared)
         return StatusEnum.prepared
 
@@ -327,7 +358,13 @@ async def _write_script(
         except KeyError as msg:
             raise CMMissingScriptInputError(f"{script.fullname} missing an input: {msg}") from msg
         command = f"{config.butler.butler_bin} associate {butler_repo} {output_coll}"
-        await write_bash_script(script_url, command, prepend="#!/usr/bin/env bash\n", **data_dict)
+
+        template_values = {
+            "script_method": script.run_method.name,
+            **data_dict,
+        }
+
+        await write_bash_script(script_url, command, values=template_values)
         await script.update_values(session, status=StatusEnum.prepared)
         return StatusEnum.prepared
 
@@ -378,7 +415,13 @@ async def _write_script(
             raise CMMissingScriptInputError(f"{script.fullname} missing an input: {msg}") from msg
         command = f"{config.butler.butler_bin} associate {butler_repo} {output_coll}"
         command += f" --collections {input_coll}"
-        await write_bash_script(script_url, command, prepend="#!/usr/bin/env bash\n", **data_dict)
+
+        template_values = {
+            "script_method": script.run_method.name,
+            **data_dict,
+        }
+
+        await write_bash_script(script_url, command, values=template_values)
         await script.update_values(session, script_url=script_url, status=StatusEnum.prepared)
         return StatusEnum.prepared
 
@@ -450,7 +493,13 @@ async def _write_script(
         command = f"{config.butler.butler_bin} collection-chain {butler_repo} {output_coll}"
         for prereq_coll_ in prereq_colls:
             command += f" {prereq_coll_}"
-        await write_bash_script(script_url, command, prepend="#!/usr/bin/env bash\n", **data_dict)
+
+        template_values = {
+            "script_method": script.run_method.name,
+            **data_dict,
+        }
+
+        await write_bash_script(script_url, command, values=template_values)
         await script.update_values(session, script_url=script_url, status=StatusEnum.prepared)
         return StatusEnum.prepared
 
@@ -483,32 +532,13 @@ async def _write_script(
         parent: ElementMixin,
         **kwargs: Any,
     ) -> StatusEnum:
-        specification = await script.get_specification(session)
         resolved_cols = await script.resolve_collections(session)
         data_dict = await script.data_dict(session)
         prod_area = os.path.expandvars(data_dict["prod_area"])
         script_url = await self._set_script_files(session, script, prod_area)
         butler_repo = data_dict["butler_repo"]
-        lsst_distrib_dir = data_dict["lsst_distrib_dir"]
-        lsst_version = data_dict["lsst_version"]
         usage_graph_url = os.path.expandvars(f"{prod_area}/{parent.fullname}/resource_usage.qgraph")
 
-        resource_usage_script_template = await specification.get_script_template(
-            session,
-            data_dict["resource_usage_script_template"],
-        )
-        prepend = resource_usage_script_template.data["text"].replace(  # type: ignore
-            "{lsst_version}",
-            lsst_version,
-        )
-        prepend = prepend.replace("{lsst_distrib_dir}", lsst_distrib_dir)
-        if "custom_lsst_setup" in data_dict:  # pragma: no cover
-            custom_lsst_setup = data_dict["custom_lsst_setup"]
-            prepend += f"\n{custom_lsst_setup}"
-
-        # Strip leading/trailing spaces just in case
-        prepend = "\n".join([line.strip() for line in prepend.splitlines()])
-
         command = (
             f"{config.bps.resource_usage_bin} {butler_repo} {usage_graph_url} "
             f"{resolved_cols['campaign_output']} --output {resolved_cols['campaign_resource_usage']};"
@@ -516,7 +546,12 @@ async def _write_script(
             f"-o {resolved_cols['campaign_resource_usage']} --register-dataset-types -j {config.bps.n_jobs}"
         )
 
-        await write_bash_script(script_url, command, prepend=prepend)
+        template_values = {
+            "script_method": script.run_method.name,
+            **data_dict,
+        }
+
+        await write_bash_script(script_url, command, values=template_values)
 
         return StatusEnum.prepared
 
@@ -554,32 +589,13 @@ async def _write_script(
         parent: ElementMixin,
         **kwargs: Any,
     ) -> StatusEnum:
-        specification = await script.get_specification(session)
         resolved_cols = await script.resolve_collections(session)
         data_dict = await script.data_dict(session)
         prod_area = os.path.expandvars(data_dict["prod_area"])
         script_url = await self._set_script_files(session, script, prod_area)
         butler_repo = data_dict["butler_repo"]
-        lsst_distrib_dir = data_dict["lsst_distrib_dir"]
-        lsst_version = data_dict["lsst_version"]
         hips_maps_graph_url = os.path.expandvars(f"{prod_area}/{parent.fullname}/hips_maps.qgraph")
 
-        hips_maps_script_template = await specification.get_script_template(
-            session,
-            data_dict["hips_maps_script_template"],
-        )
-        prepend = hips_maps_script_template.data["text"].replace(  # type: ignore
-            "{lsst_version}",
-            lsst_version,
-        )
-        prepend = prepend.replace("{lsst_distrib_dir}", lsst_distrib_dir)
-        if "custom_lsst_setup" in data_dict:  # pragma: no cover
-            custom_lsst_setup = data_dict["custom_lsst_setup"]
-            prepend += f"\n{custom_lsst_setup}"
-
-        # Strip leading/trailing spaces just in case
-        prepend = "\n".join([line.strip() for line in prepend.splitlines()])
-
         hips_pipeline_yaml = await Path(
             os.path.expandvars("${CM_CONFIGS}") + data_dict["hips_pipeline_yaml_path"]
         ).resolve()
@@ -622,7 +638,12 @@ async def _write_script(
         # Strip leading/trailing spaces just in case
         command = "\n".join([line.strip() for line in command.splitlines()])
 
-        await write_bash_script(script_url, command, prepend=prepend)
+        template_values = {
+            "script_method": script.run_method.name,
+            **data_dict,
+        }
+
+        await write_bash_script(script_url, command, values=template_values)
 
         return StatusEnum.prepared
 
@@ -677,7 +698,13 @@ async def _write_script(
         except KeyError as msg:
             raise CMMissingScriptInputError(f"{script.fullname} missing an input: {msg}") from msg
         command = f"{config.bps.pipetask_bin} validate {butler_repo} {input_coll} {output_coll}"
-        await write_bash_script(script_url, command, prepend="#!/usr/bin/env bash\n", **data_dict)
+
+        template_values = {
+            "script_method": script.run_method.name,
+            **data_dict,
+        }
+
+        await write_bash_script(script_url, command, values=template_values)
         await script.update_values(session, script_url=script_url, status=StatusEnum.prepared)
         return StatusEnum.prepared
 
diff --git a/src/lsst/cmservice/main.py b/src/lsst/cmservice/main.py
index 3f488818e..cdbfb8c0f 100644
--- a/src/lsst/cmservice/main.py
+++ b/src/lsst/cmservice/main.py
@@ -118,10 +118,10 @@ async def lifespan(app: FastAPI) -> AsyncGenerator:
     lifespan=lifespan,
     title=config.asgi.title,
     version=__version__,
-    openapi_url="/openapi.json",
+    openapi_url="/docs/openapi.json",
     openapi_tags=tags_metadata,
     docs_url="/docs",
-    redoc_url="/redoc",
+    redoc_url=None,
 )
 
 app.add_middleware(XForwardedMiddleware)
diff --git a/src/lsst/cmservice/models/merged_wms_task_report.py b/src/lsst/cmservice/models/merged_wms_task_report.py
index b8bb33734..3b974828c 100644
--- a/src/lsst/cmservice/models/merged_wms_task_report.py
+++ b/src/lsst/cmservice/models/merged_wms_task_report.py
@@ -5,7 +5,7 @@
 from pydantic import BaseModel, ConfigDict
 
 
-class MergedWmsTaskReport(BaseModel):  # pylint: disable=too-many-instance-attributes
+class MergedWmsTaskReport(BaseModel):
     """Pydantic model for combining data on WmsTasks"""
 
     model_config = ConfigDict(from_attributes=True)
diff --git a/src/lsst/cmservice/templates/bps_submit_yaml.j2 b/src/lsst/cmservice/templates/bps_submit_yaml.j2
new file mode 100644
index 000000000..307b58687
--- /dev/null
+++ b/src/lsst/cmservice/templates/bps_submit_yaml.j2
@@ -0,0 +1,57 @@
+project: {{ project }}
+campaign: {{ campaign }}
+LSST_VERSION: {{ lsst_version }}
+submitPath: {{ submit_path }}
+{%- if custom_lsst_setup %}
+{{ custom_lsst_setup }}
+{%- endif %}
+pipelineYaml: {{ pipeline_yaml }}
+executionButler:
+  queue: SLAC_Rubin_Merge
+  requestMemory: 64000
+  command2: ''
+  command3: ''
+{%- if include_configs | length > 0 %}
+includeConfigs:
+{%- for config in include_configs %}
+- {{ config }}
+{%- endfor %}
+{%- endif %}
+payload:
+  payloadName: {{ payload.name }}
+  butlerConfig: {{ payload.butler_config }}
+  inCollection: {{ payload.input_collection }}
+  outputRun: {{ payload.output_run_collection }}
+  {%- if payload.data_query %}
+  dataQuery: {{ payload.data_query | replace("\n", " ") | trim }}
+  {%- endif %}
+  {%- if payload.extra_args %}
+  extra_args: {{ payload.extra_args }}
+  {%- endif %}
+pipetaskOutput: ''
+{%- if extra_qgraph_options %}
+extraQgraphOptions: {{ extra_qgraph_options | replace("\n", " ") | trim }}
+{%- endif %}
+{%- if extra_yaml_literals|length > 0 %}
+{%- for yaml_literal in extra_yaml_literals %}
+{{ yaml_literal }}
+{%- endfor %}
+{%- endif %}
+{%- if wms == "htcondor" %}
+wmsServiceClass: lsst.ctrl.bps.htcondor.HTCondorService
+{%- if compute_site == "usdf" %}
+site:
+  s3df:
+    profile:
+      condor:
+        +Walltime: 7200
+memoryMultiplier: 4.
+numberOfRetries: 3
+memoryLimit: 400000
+{%- endif %}
+{%- endif %}
+{%- if wms == "panda" %}
+wmsServiceClass: lsst.ctrl.bps.panda.PanDAService
+{%- if compute_site == "usdf" %}
+{%- endif %}
+{%- endif %}
diff --git a/src/lsst/cmservice/templates/wms_submit_sh.j2 b/src/lsst/cmservice/templates/wms_submit_sh.j2
new file mode 100644
index 000000000..fae24484a
--- /dev/null
+++ b/src/lsst/cmservice/templates/wms_submit_sh.j2
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+{%- if script_method == "bash" %}
+# Assuming native environment already setup
+
+{%- elif script_method == "htcondor" %}
+
+# setup LSST env.
+export LSST_VERSION='{{ lsst_version }}'
+export LSST_DISTRIB_DIR='{{ lsst_distrib_dir }}'
+source ${LSST_DISTRIB_DIR}/${LSST_VERSION}/loadLSST.bash
+setup lsst_distrib
+
+{%- elif script_method == "panda" %}
+
+# setup PanDA env.
+latest_panda=$(ls -td /cvmfs/sw.lsst.eu/linux-x86_64/panda_env/v* | head -1)
+source ${latest_panda}/setup_panda_usdf.sh ${WEEKLY}
+panda_auth status
+
+{%- endif %}
+{%- if custom_lsst_setup %}
+
+{{ custom_lsst_setup }}
+
+{%- endif %}
+{{ command }}
+{%- if append %}
+
+{{ append }}
+{%- endif %}
diff --git a/src/lsst/cmservice/web_app/app.py b/src/lsst/cmservice/web_app/app.py
index c5f54af92..174b8bdd6 100644
--- a/src/lsst/cmservice/web_app/app.py
+++ b/src/lsst/cmservice/web_app/app.py
@@ -32,8 +32,8 @@ async def lifespan(_: FastAPI) -> AsyncGenerator:
     """Hook FastAPI init/cleanups."""
     # Dependency inits before app starts running
     await db_session_dependency.initialize(config.db.url, config.db.password)
-    assert db_session_dependency._engine is not None  # pylint: disable=protected-access
-    db_session_dependency._engine.echo = config.db.echo  # pylint: disable=protected-access
+    assert db_session_dependency._engine is not None
+    db_session_dependency._engine.echo = config.db.echo
 
     # App runs here...
     yield
diff --git a/tests/cli/util_functions.py b/tests/cli/util_functions.py
index 960c6e3fb..293bcda8d 100644
--- a/tests/cli/util_functions.py
+++ b/tests/cli/util_functions.py
@@ -237,10 +237,7 @@ def check_update_methods(
 ) -> None:
     result = runner.invoke(
         client_top,
-        f"{entry_class_name} update data_dict "
-        "--output yaml "
-        f"--row_id {entry.id} "
-        "--update_dict test:dummy",
+        f"{entry_class_name} update data_dict --output yaml --row_id {entry.id} --update_dict test:dummy",
     )
     check = check_and_parse_result(result, dict)
     assert check["test"] == "dummy", "update_data_dict failed"
@@ -267,10 +264,7 @@ def check_update_methods(
 
     result = runner.invoke(
         client_top,
-        f"{entry_class_name} update collections "
-        "--output yaml "
-        f"--row_id {entry.id} "
-        "--update_dict test:dummy",
+        f"{entry_class_name} update collections --output yaml --row_id {entry.id} --update_dict test:dummy",
     )
     check = check_and_parse_result(result, dict)
     assert check["test"] == "dummy", "update_collections failed"
@@ -303,20 +297,14 @@ def check_update_methods(
 
     result = runner.invoke(
         client_top,
-        f"{entry_class_name} update child_config "
-        f"--row_id {entry.id} "
-        "--output yaml "
-        "--update_dict test:dummy",
+        f"{entry_class_name} update child_config --row_id {entry.id} --output yaml --update_dict test:dummy",
     )
     check = check_and_parse_result(result, dict)
     assert check["test"] == "dummy", "update_child_config failed"
 
     result = runner.invoke(
         client_top,
-        f"{entry_class_name} update child_config "
-        f"--row_id -1 "
-        "--output yaml "
-        "--update_dict test:dummy",
+        f"{entry_class_name} update child_config --row_id -1 --output yaml --update_dict test:dummy",
     )
     expect_failed_result(result, 1)
 
@@ -331,10 +319,7 @@ def check_update_methods(
 
     result = runner.invoke(
         client_top,
-        f"{entry_class_name} update spec_aliases "
-        "--output yaml "
-        f"--row_id {entry.id} "
-        "--update_dict test:dummy",
+        f"{entry_class_name} update spec_aliases --output yaml --row_id {entry.id} --update_dict test:dummy",
     )
     # FIXME: is this the return type we want?
     check_spec = check_and_parse_result(result, entry_class)
diff --git a/tests/common/test_butler.py b/tests/common/test_butler.py
new file mode 100644
index 000000000..2294d5eef
--- /dev/null
+++ b/tests/common/test_butler.py
@@ -0,0 +1,67 @@
+import json
+from typing import Any
+
+import pytest
+
+from lsst.cmservice.common.butler import get_butler_config
+from lsst.cmservice.config import config
+from lsst.daf.butler.registry import RegistryConfig
+
+
+@pytest.fixture()
+def mock_butler_environment(tmp_path: Any, monkeypatch: Any) -> None:
+    repo_mock_path = tmp_path / "repo" / "mock"
+    repo_mock_path.mkdir(parents=True)
+    repo_mock_butler_yaml = repo_mock_path / "butler.yaml"
+
+    repo_yaml = """---
+datastore:
+  cls: lsst.daf.butler.datastores.inMemoryDatastore.InMemoryDatastore
+registry:
+  db: "sqlite:///:memory:"
+"""
+    repo_mock_butler_yaml.write_text(repo_yaml)
+
+    repo_mockgres_butler_yaml = repo_mock_path / "butler+postgres.yaml"
+
+    repo_yaml = """---
+datastore:
+  cls: lsst.daf.butler.datastores.inMemoryDatastore.InMemoryDatastore
+registry:
+  db: postgresql://localhost:5432/mockdb
+"""
+    repo_mockgres_butler_yaml.write_text(repo_yaml)
+
+    daf_butler_repositories = {
+        "/repo/mock": f"{repo_mock_path}",
+        "/repo/mockgres": f"{repo_mockgres_butler_yaml}",
+        "mockbargo": "s3://bucket/prefix/object.yaml",
+    }
+    monkeypatch.setenv("DAF_BUTLER_REPOSITORIES", json.dumps(daf_butler_repositories))
+
+
+@pytest.fixture
+def mock_db_auth_file(tmp_path: Any, monkeypatch: Any) -> None:
+    mock_auth_path = tmp_path / "db-auth.yaml"
+    mock_auth_path.write_text("""---
+    - url: postgresql://localhost:5432/mockdb
+      username: mocker_mockerson
+      password: letmein
+    """)
+
+    monkeypatch.setattr(config.butler, "authentication_file", str(mock_auth_path))
+
+
+@pytest.mark.asyncio
+async def test_butler_creation_without_db_auth_file(mock_butler_environment: Any) -> None:
+    bc = await get_butler_config("/repo/mock", without_datastore=True)
+    assert bc[".registry.db"] == "sqlite:///:memory:"
+
+
+@pytest.mark.asyncio
+async def test_butler_creation_with_db_auth_file(
+    mock_butler_environment: Any, mock_db_auth_file: Any
+) -> None:
+    bc = await get_butler_config("/repo/mockgres", without_datastore=True)
+    rc = RegistryConfig(bc)
+    assert "mocker_mockerson" in rc.connectionString
diff --git a/tests/common/test_common.py b/tests/common/test_common.py
index 60fa64a55..632326c57 100644
--- a/tests/common/test_common.py
+++ b/tests/common/test_common.py
@@ -31,9 +31,8 @@ async def test_common_bash() -> None:
     the_script = await write_bash_script(
         "temp.sh",
         "ls",
-        prepend="#!/usr/bin/env bash",
-        append="# have a nice day",
         fake=True,
+        values=dict(append="# have a nice day", script_method="bash"),
     )
 
     await run_bash_job(the_script, "temp.log", "temp.stamp")
@@ -113,10 +112,10 @@ async def test_common_htcondor() -> None:
     """Test common.htcondor functions"""
 
     _ht_condor_log = await write_htcondor_script(
-        "htcondor_temp.sh",
-        "htcondor_temp.log",
-        "script_temp.sh",
-        "script_temp.log",
+        Path("htcondor_temp.sh"),
+        Path("htcondor_temp.log"),
+        Path("script_temp.sh"),
+        Path("script_temp.log"),
     )
 
     with pytest.raises(CMHTCondorSubmitError):
diff --git a/tests/common/test_config.py b/tests/common/test_config.py
index 1d56f258e..77d69bbff 100644
--- a/tests/common/test_config.py
+++ b/tests/common/test_config.py
@@ -14,21 +14,18 @@ def test_config_nested_partial_update(monkeypatch: Any) -> None:
     config_a = Configuration()
     assert not config_a.db.echo
     assert config_a.htcondor.condor_q_bin == "condor_q"
-    assert config_a.slurm.sacct_bin == "sacct"
     assert config_a.asgi.port == 8080
     assert config_a.logging.profile == "development"
 
     monkeypatch.setenv("LOGGING__PROFILE", "production")
     monkeypatch.setenv("ASGI__PORT", "5000")
     monkeypatch.setenv("HTCONDOR__CONDOR_Q_BIN", "/usr/local/bin/condor_q")
-    monkeypatch.setenv("SLURM__SACCT_BIN", "/opt/slurm/bin/sacct")
     monkeypatch.setenv("DB__ECHO", "1")
 
     # Partial updates in nested configuration models
     config_b = Configuration()
     assert config_b.db.echo
     assert config_b.htcondor.condor_q_bin == "/usr/local/bin/condor_q"
-    assert config_b.slurm.sacct_bin == "/opt/slurm/bin/sacct"
     assert config_b.asgi.port == 5000
     assert config_b.logging.profile == "production"
 
diff --git a/tests/conftest.py b/tests/conftest.py
index c197785d9..c7d182919 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -13,14 +13,21 @@
 from sqlalchemy.ext.asyncio import AsyncEngine
 
 from lsst.cmservice import db, main
-from lsst.cmservice.config import config
+from lsst.cmservice.common.enums import ScriptMethodEnum
+from lsst.cmservice.config import config as config_
+
+
+@pytest.fixture(autouse=True)
+def set_app_config(monkeypatch: Any) -> None:
+    """Set any required app configuration for testing."""
+    config_.script_handler = ScriptMethodEnum.bash
 
 
 @pytest_asyncio.fixture(name="engine")
 async def engine_fixture() -> AsyncIterator[AsyncEngine]:
     """Return a SQLAlchemy AsyncEngine configured to talk to the app db."""
     logger = structlog.get_logger(__name__)
-    the_engine = create_database_engine(config.db.url, config.db.password)
+    the_engine = create_database_engine(config_.db.url, config_.db.password)
     await initialize_database(the_engine, logger, schema=db.Base.metadata, reset=True)
     yield the_engine
     await the_engine.dispose()
diff --git a/tests/db/conftest.py b/tests/db/conftest.py
new file mode 100644
index 000000000..6931c4b51
--- /dev/null
+++ b/tests/db/conftest.py
@@ -0,0 +1,18 @@
+import importlib
+import sys
+from collections.abc import Generator
+
+import pytest
+
+
+@pytest.fixture(autouse=True, scope="function")
+def import_deps() -> Generator:
+    _ = importlib.import_module("lsst.cmservice.handlers.interface")
+    _ = importlib.import_module("lsst.cmservice.handlers.jobs")
+    _ = importlib.import_module("lsst.cmservice.handlers.functions")
+    _ = importlib.import_module("lsst.cmservice.handlers.script_handler")
+    yield
+    del sys.modules["lsst.cmservice.handlers.interface"]
+    del sys.modules["lsst.cmservice.handlers.jobs"]
+    del sys.modules["lsst.cmservice.handlers.functions"]
+    del sys.modules["lsst.cmservice.handlers.script_handler"]
diff --git a/tests/db/test_campaign.py b/tests/db/test_campaign.py
index 31608f465..c908fe96f 100644
--- a/tests/db/test_campaign.py
+++ b/tests/db/test_campaign.py
@@ -151,4 +151,4 @@ async def test_campaign_db(engine: AsyncEngine) -> None:
         await check_queue(session, entry)
 
         # cleanup
-        await cleanup(session)
+        await cleanup(session, check_cascade=True)
diff --git a/tests/db/test_daemon.py b/tests/db/test_daemon.py
index d226f0d4a..c31c82a7e 100644
--- a/tests/db/test_daemon.py
+++ b/tests/db/test_daemon.py
@@ -1,7 +1,8 @@
 import os
+import uuid
+from asyncio import sleep
 from datetime import datetime
 
-import pause
 import pytest
 import structlog
 from safir.database import create_async_session
@@ -27,8 +28,8 @@ async def test_daemon_db(engine: AsyncEngine) -> None:
 
         campaign = await interface.load_and_create_campaign(
             session,
-            "examples/example_trivial.yaml",
-            "trivial_panda",
+            "tests/fixtures/seeds/example_trivial.yaml",
+            f"trivial_panda_{uuid.uuid1().int}",
             "test_daemon",
             "trivial_panda#campaign",
         )
@@ -52,7 +53,7 @@ async def test_daemon_db(engine: AsyncEngine) -> None:
 
         assert campaign.status.value >= StatusEnum.running.value
 
-        pause.sleep(2)
+        await sleep(2)
         await queue_entry.update_values(
             session,
             time_next_check=datetime.now(),
@@ -60,6 +61,7 @@ async def test_daemon_db(engine: AsyncEngine) -> None:
         await session.commit()
 
         await daemon_iteration(session)
+        await sleep(2)
         await session.refresh(campaign)
 
         assert campaign.status == StatusEnum.accepted
diff --git a/tests/db/test_handlers.py b/tests/db/test_handlers.py
index c52f83284..572191e31 100644
--- a/tests/db/test_handlers.py
+++ b/tests/db/test_handlers.py
@@ -1,4 +1,6 @@
+import importlib
 import os
+import sys
 from pathlib import Path
 from typing import Any
 
@@ -10,7 +12,6 @@
 
 from lsst.cmservice import db
 from lsst.cmservice.common.enums import LevelEnum, StatusEnum
-from lsst.cmservice.handlers import interface, jobs
 
 from .util_functions import cleanup, create_tree
 
@@ -23,6 +24,7 @@ async def check_run_script(
     spec_block_name: str,
     **kwargs: Any,
 ) -> db.Script:
+    interface = sys.modules["lsst.cmservice.handlers"].interface
     script = await db.Script.create_row(
         session,
         parent_name=parent.fullname,
@@ -51,6 +53,7 @@ async def check_script(
     spec_block_name: str,
     **kwargs: Any,
 ) -> db.Script:
+    interface = sys.modules["lsst.cmservice.handlers"].interface
     script = await db.Script.create_row(
         session,
         parent_name=parent.fullname,
@@ -90,6 +93,7 @@ async def check_script(
 async def test_handlers_campaign_level_db(
     engine: AsyncEngine,
     tmp_path: Path,
+    import_deps: Any,
 ) -> None:
     """Test to run the write and purge methods of various scripts"""
     temp_dir = str(tmp_path / "archive")
@@ -122,8 +126,6 @@ async def test_handlers_campaign_level_db(
 
         data = dict(
             lsst_distrib_dir="lsst_distrib_dir",
-            resource_usage_script_template="stack_script_template",
-            hips_maps_script_template="stack_script_template",
             hips_pipeline_yaml_path="/stack_files/highres_hips_rc2.yaml",
             hips_pipeline_config_path="/stack_files/gen_hips_both_rc2.yaml",
         )
@@ -173,6 +175,7 @@ async def test_handlers_campaign_level_db(
 async def test_handlers_step_level_db(
     engine: AsyncEngine,
     tmp_path: Path,
+    import_deps: Any,
     monkeypatch: MonkeyPatch,
 ) -> None:
     """Test to run the write and purge methods of various scripts"""
@@ -213,6 +216,7 @@ async def test_handlers_step_level_db(
 async def test_handlers_group_level_db(
     engine: AsyncEngine,
     tmp_path: Path,
+    import_deps: Any,
     monkeypatch: MonkeyPatch,
 ) -> None:
     """Test to run the write and purge methods of various scripts"""
@@ -245,11 +249,6 @@ async def test_handlers_group_level_db(
 
         dict(
             lsst_distrib_dir="lsst_distrib_dir",
-            bps_core_yaml_template="bps_core_yaml_template",
-            bps_core_script_template="bps_core_script_template",
-            bps_panda_script_template="bps_panda_script_template",
-            bps_htcondor_script_template="bps_htcondor_script_template",
-            manifest_script_template="stack_script_template",
         )
 
         run_jobs = await check_run_script(session, group, "run", "run_jobs", collections=collections)
@@ -275,6 +274,8 @@ async def test_handlers_job_level_db(
     tmp_path: Path,
 ) -> None:
     """Test to run the write and purge methods of various scripts"""
+    interface = importlib.import_module("lsst.cmservice.handlers.interface")
+    jobs = importlib.import_module("lsst.cmservice.handlers.jobs")
     temp_dir = str(tmp_path / "archive")
 
     logger = structlog.get_logger(__name__)
@@ -303,11 +304,6 @@ async def test_handlers_job_level_db(
 
         data = dict(
             lsst_distrib_dir="lsst_distrib_dir",
-            bps_core_yaml_template="bps_core_yaml_template",
-            bps_core_script_template="bps_core_script_template",
-            bps_panda_script_template="bps_panda_script_template",
-            bps_htcondor_script_template="bps_htcondor_script_template",
-            manifest_script_template="stack_script_template",
         )
 
         await check_script(
@@ -375,7 +371,7 @@ async def test_handlers_job_level_db(
         )
         assert status == StatusEnum.waiting
 
-        assert jobs.PandaScriptHandler.get_job_id({"Run Id": 322}) == 322  # type: ignore
+        assert jobs.PandaScriptHandler.get_job_id({"Run Id": 322}) == 322
         assert jobs.HTCondorScriptHandler.get_job_id({"Submit dir": "dummy"}) == "dummy"
 
         await cleanup(session, check_cascade=True)
diff --git a/tests/db/test_job.py b/tests/db/test_job.py
index bd4737581..537d641fd 100644
--- a/tests/db/test_job.py
+++ b/tests/db/test_job.py
@@ -1,3 +1,4 @@
+import importlib
 import os
 import uuid
 
@@ -10,7 +11,6 @@
 from lsst.cmservice import db
 from lsst.cmservice.common import errors
 from lsst.cmservice.common.enums import LevelEnum, StatusEnum
-from lsst.cmservice.handlers import interface
 
 from .util_functions import (
     check_get_methods,
@@ -25,7 +25,7 @@
 @pytest.mark.asyncio()
 async def test_job_db(engine: AsyncEngine) -> None:
     """Test `job` db table."""
-
+    interface = importlib.import_module("lsst.cmservice.handlers.interface")
     # generate a uuid to avoid collisions
     uuid_int = uuid.uuid1().int
     logger = structlog.get_logger(__name__)
diff --git a/tests/db/test_micro.py b/tests/db/test_micro.py
index 99b13c997..a0e5dcbb6 100644
--- a/tests/db/test_micro.py
+++ b/tests/db/test_micro.py
@@ -1,3 +1,4 @@
+import importlib
 import os
 from pathlib import Path
 
@@ -9,8 +10,6 @@
 
 from lsst.cmservice.common import errors
 from lsst.cmservice.common.enums import ScriptMethodEnum, StatusEnum
-from lsst.cmservice.handlers import interface
-from lsst.cmservice.handlers.script_handler import ScriptHandler
 
 from .util_functions import cleanup
 
@@ -26,6 +25,8 @@ async def test_micro_db(
     monkeypatch: MonkeyPatch,
 ) -> None:
     """Test fake end to end run using example/example_micro.yaml"""
+    ScriptHandler = importlib.import_module("lsst.cmservice.handlers.script_handler").ScriptHandler
+    interface = importlib.import_module("lsst.cmservice.handlers.interface")
     monkeypatch.setattr("lsst.cmservice.config.config.butler.mock", True)
 
     orig_method = ScriptHandler.default_method
@@ -45,15 +46,6 @@ async def test_micro_db(
         with pytest.raises(errors.CMSpecificationError):
             await specification.get_script_template(session, "bad")
 
-        script_template = await specification.get_script_template(session, "bps_core_script_template")
-        assert script_template.name == "bps_core_script_template", "Script template name mismatch"
-
-        await script_template.update_from_file(
-            session,
-            script_template.name,
-            "examples/templates/example_bps_core_script_template.yaml",
-        )
-
         campaign = await interface.load_and_create_campaign(
             session,
             "examples/example_hsc_micro.yaml",
diff --git a/tests/db/test_pipetask_error_type.py b/tests/db/test_pipetask_error_type.py
index 1674b8aa0..eb87efcc0 100644
--- a/tests/db/test_pipetask_error_type.py
+++ b/tests/db/test_pipetask_error_type.py
@@ -1,3 +1,4 @@
+import importlib
 import os
 
 import pytest
@@ -7,7 +8,6 @@
 from sqlalchemy.ext.asyncio import AsyncEngine
 
 from lsst.cmservice import db
-from lsst.cmservice.handlers import functions, interface
 
 from .util_functions import cleanup, delete_all_rows
 
@@ -20,6 +20,8 @@ async def test_error_match_db(engine: AsyncEngine) -> None:
     fake error which is not in the database.
     """
 
+    interface = importlib.import_module("lsst.cmservice.handlers.interface")
+    functions = importlib.import_module("lsst.cmservice.handlers.functions")
     logger = structlog.get_logger(__name__)
     async with engine.begin():
         session = await create_async_session(engine, logger)
@@ -57,15 +59,15 @@ async def test_error_match_db(engine: AsyncEngine) -> None:
         # Here we test that the same error with a different pipetask name will
         # not match. Let's consider the same error, but on task "isr"
 
-        assert (
-            e1.match("isr", known_error["diagnostic_message"]) is False
-        ), "Failure to identify non-matching pipetask name"
+        assert e1.match("isr", known_error["diagnostic_message"]) is False, (
+            "Failure to identify non-matching pipetask name"
+        )
 
         # Here we test that the same pipetask name but different error does not
         # match.
-        assert (
-            e1.match(known_error["task_name"], "A different error message") is False
-        ), "Failure to identify separate errors with the same associated pipetask"
+        assert e1.match(known_error["task_name"], "A different error message") is False, (
+            "Failure to identify separate errors with the same associated pipetask"
+        )
 
         # Here we test that a different valid PipetaskError does not match to
         # the wrong PipetaskErrorType
@@ -111,6 +113,7 @@ async def test_error_match_db(engine: AsyncEngine) -> None:
 async def test_error_type_db(engine: AsyncEngine) -> None:
     """Test `error_type` db table."""
 
+    interface = importlib.import_module("lsst.cmservice.handlers.interface")
     logger = structlog.get_logger(__name__)
     async with engine.begin():
         session = await create_async_session(engine, logger)
diff --git a/tests/db/test_reports.py b/tests/db/test_reports.py
index 952ffdde8..d4a2cffe7 100644
--- a/tests/db/test_reports.py
+++ b/tests/db/test_reports.py
@@ -1,3 +1,4 @@
+import importlib
 import os
 import uuid
 
@@ -8,7 +9,6 @@
 
 from lsst.cmservice import db
 from lsst.cmservice.common.enums import LevelEnum, StatusEnum
-from lsst.cmservice.handlers import functions, interface
 
 from .util_functions import (
     cleanup,
@@ -19,6 +19,8 @@
 @pytest.mark.asyncio()
 async def test_reports_db(engine: AsyncEngine) -> None:
     """Test `job` db table."""
+    interface = importlib.import_module("lsst.cmservice.handlers.interface")
+    functions = importlib.import_module("lsst.cmservice.handlers.functions")
 
     # generate a uuid to avoid collisions
     uuid_int = uuid.uuid1().int
diff --git a/tests/db/util_functions.py b/tests/db/util_functions.py
index 8cfeb5f0d..5432c4b7e 100644
--- a/tests/db/util_functions.py
+++ b/tests/db/util_functions.py
@@ -1,3 +1,4 @@
+import importlib
 from typing import TypeAlias
 
 import pytest
@@ -6,7 +7,6 @@
 from lsst.cmservice import db
 from lsst.cmservice.common import errors
 from lsst.cmservice.common.enums import LevelEnum, StatusEnum, TableEnum
-from lsst.cmservice.handlers import interface
 
 
 async def add_scripts(
@@ -43,6 +43,7 @@ async def create_tree(
     level: LevelEnum,
     uuid_int: int,
 ) -> None:
+    interface = importlib.import_module("lsst.cmservice.handlers.interface")
     specification = await interface.load_specification(session, "examples/empty_config.yaml")
     _ = await specification.get_block(session, "campaign")
 
@@ -107,7 +108,7 @@ async def create_tree(
     if level.value <= LevelEnum.group.value:
         return
 
-    jobs = [
+    jobs_ = [
         await db.Job.create_row(
             session,
             name=f"job_{uuid_int}",
@@ -117,8 +118,8 @@ async def create_tree(
         for group_ in groups
     ]
 
-    for job_ in jobs:
-        await add_scripts(session, job_)
+    for job in jobs_:
+        await add_scripts(session, job)
 
     return
 
@@ -291,6 +292,7 @@ async def check_scripts(
     session: async_scoped_session,
     entry: db.ElementMixin,
 ) -> None:
+    interface = importlib.import_module("lsst.cmservice.handlers.interface")
     scripts = await entry.get_scripts(session)
     assert len(scripts) == 2, f"Expected exactly two scripts for {entry.fullname} got {len(scripts)}"
 
@@ -376,6 +378,7 @@ async def check_get_methods(
     entry_class: TypeAlias = db.ElementMixin,
     parent_class: TypeAlias = db.ElementMixin,
 ) -> None:
+    interface = importlib.import_module("lsst.cmservice.handlers.interface")
     check_getall_nonefound = await entry_class.get_rows(
         session,
         parent_name="bad",
diff --git a/tests/fixtures/seeds/example_trivial.yaml b/tests/fixtures/seeds/example_trivial.yaml
new file mode 100644
index 000000000..43a6a510d
--- /dev/null
+++ b/tests/fixtures/seeds/example_trivial.yaml
@@ -0,0 +1,33 @@
+- Imports:
+      - "${CM_CONFIGS}/example_standard_scripts.yaml"
+      - "${CM_CONFIGS}/example_trivial_elements.yaml"
+      - "${CM_CONFIGS}/example_trivial_steps.yaml"
+- SpecBlock:
+      name: trivial_campaign
+      includes: ["trivial_campaign_base"]
+      collections:
+          campaign_source: HSC/raw/RC2
+      steps:
+          - Step:
+                name: trivial_step
+                spec_block: trivial_step
+                child_config:
+                    base_query: "instrument = 'HSC'"
+                    split_method: no_split
+      data:
+          butler_repo: '/repo/main'
+          prod_area: 'output/archive'
+          data_query: "instrument = 'HSC' AND exposure in (30504, 30502) AND detector in (45, 46, 47, 48)"
+          lsst_version: w_2023_46
+- Specification:
+      name: trivial_panda
+      spec_aliases:
+          campaign: trivial_campaign
+          bps_submit_script: bps_panda_submit_script
+          bps_report_script: bps_panda_report_script
+- Specification:
+      name: trivial_htcondor
+      spec_aliases:
+          campaign: trivial_campaign
+          bps_submit_script: bps_htcondor_submit_script
+          bps_report_script: bps_htcondor_report_script
diff --git a/uv.lock b/uv.lock
index 7a1cf1de6..32ef1b99f 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1,5 +1,6 @@
 version = 1
-requires-python = ">=3.11"
+revision = 1
+requires-python = ">=3.11, <3.13"
 
 [[package]]
 name = "aiofiles"
@@ -33,38 +34,37 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/ae/48/541ccece0e593e24ee371dec0c33c23718bc010b04e998693e4c19091258/aiokafka-0.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b815b2e5fed9912f1231be6196547a367b9eb3380b487ff5942f0c73a3fb5c", size = 1213231 },
     { url = "https://files.pythonhosted.org/packages/99/3f/75bd0faa77dfecce34dd1c0edd317b608518b096809736f9987dd61f4cec/aiokafka-0.12.0-cp312-cp312-win32.whl", hash = "sha256:5a907abcdf02430df0829ac80f25b8bb849630300fa01365c76e0ae49306f512", size = 347752 },
     { url = "https://files.pythonhosted.org/packages/ef/97/e2513a0c10585e51d4d9b42c9dd5f5ab15dfe150620a4893a2c6c20f0f4a/aiokafka-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:fdbd69ec70eea4a8dfaa5c35ff4852e90e1277fcc426b9380f0b499b77f13b16", size = 366068 },
-    { url = "https://files.pythonhosted.org/packages/30/84/f1f7e603cd07e877520b5a1e48e006cbc1fe448806cabbaa98aa732f530d/aiokafka-0.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f9e8ab97b935ca681a5f28cf22cf2b5112be86728876b3ec07e4ed5fc6c21f2d", size = 370960 },
-    { url = "https://files.pythonhosted.org/packages/d7/c7/5237b3687198c2129c0bafa4a96cf8ae3883e20cc860125bafe16af3778e/aiokafka-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed991c120fe19fd9439f564201dd746c4839700ef270dd4c3ee6d4895f64fe83", size = 366597 },
-    { url = "https://files.pythonhosted.org/packages/6b/67/0154551292ec1c977e5def178ae5c947773e921aefb6877971e7fdf1942e/aiokafka-0.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c01abf9787b1c3f3af779ad8e76d5b74903f590593bc26f33ed48750503e7f7", size = 1152905 },
-    { url = "https://files.pythonhosted.org/packages/d9/20/69f913a76916e94c4e783dc7d0d05a25c384b25faec33e121062c62411fe/aiokafka-0.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08c84b3894d97fd02fcc8886f394000d0f5ce771fab5c498ea2b0dd2f6b46d5b", size = 1171893 },
-    { url = "https://files.pythonhosted.org/packages/16/65/41cc1b19e7dea623ef58f3bf1e2720377c5757a76d9799d53a1b5fc39255/aiokafka-0.12.0-cp313-cp313-win32.whl", hash = "sha256:63875fed922c8c7cf470d9b2a82e1b76b4a1baf2ae62e07486cf516fd09ff8f2", size = 345933 },
-    { url = "https://files.pythonhosted.org/packages/bf/0d/4cb57231ff650a01123a09075bf098d8fdaf94b15a1a58465066b2251e8b/aiokafka-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:bdc0a83eb386d2384325d6571f8ef65b4cfa205f8d1c16d7863e8d10cacd995a", size = 363194 },
 ]
 
 [[package]]
 name = "aiosqlite"
-version = "0.20.0"
+version = "0.21.0"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "typing-extensions" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/0d/3a/22ff5415bf4d296c1e92b07fd746ad42c96781f13295a074d58e77747848/aiosqlite-0.20.0.tar.gz", hash = "sha256:6d35c8c256637f4672f843c31021464090805bf925385ac39473fb16eaaca3d7", size = 21691 }
+sdist = { url = "https://files.pythonhosted.org/packages/13/7d/8bca2bf9a247c2c5dfeec1d7a5f40db6518f88d314b8bca9da29670d2671/aiosqlite-0.21.0.tar.gz", hash = "sha256:131bb8056daa3bc875608c631c678cda73922a2d4ba8aec373b19f18c17e7aa3", size = 13454 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/00/c4/c93eb22025a2de6b83263dfe3d7df2e19138e345bca6f18dba7394120930/aiosqlite-0.20.0-py3-none-any.whl", hash = "sha256:36a1deaca0cac40ebe32aac9977a6e2bbc7f5189f23f4a54d5908986729e5bd6", size = 15564 },
+    { url = "https://files.pythonhosted.org/packages/f5/10/6c25ed6de94c49f88a91fa5018cb4c0f3625f31d5be9f771ebe5cc7cd506/aiosqlite-0.21.0-py3-none-any.whl", hash = "sha256:2549cf4057f95f53dcba16f2b64e8e2791d7e1adedb13197dd8ed77bb226d7d0", size = 15792 },
 ]
 
 [[package]]
 name = "alembic"
-version = "1.14.0"
+version = "1.14.1"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "mako" },
     { name = "sqlalchemy" },
     { name = "typing-extensions" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/00/1e/8cb8900ba1b6360431e46fb7a89922916d3a1b017a8908a7c0499cc7e5f6/alembic-1.14.0.tar.gz", hash = "sha256:b00892b53b3642d0b8dbedba234dbf1924b69be83a9a769d5a624b01094e304b", size = 1916172 }
+sdist = { url = "https://files.pythonhosted.org/packages/99/09/f844822e4e847a3f0bd41797f93c4674cd4d2462a3f6c459aa528cdf786e/alembic-1.14.1.tar.gz", hash = "sha256:496e888245a53adf1498fcab31713a469c65836f8de76e01399aa1c3e90dd213", size = 1918219 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/cb/06/8b505aea3d77021b18dcbd8133aa1418f1a1e37e432a465b14c46b2c0eaa/alembic-1.14.0-py3-none-any.whl", hash = "sha256:99bd884ca390466db5e27ffccff1d179ec5c05c965cfefc0607e69f9e411cb25", size = 233482 },
+    { url = "https://files.pythonhosted.org/packages/54/7e/ac0991d1745f7d755fc1cd381b3990a45b404b4d008fc75e2a983516fbfe/alembic-1.14.1-py3-none-any.whl", hash = "sha256:1acdd7a3a478e208b0503cd73614d5e4c6efafa4e73518bb60e4f2846a37b1c5", size = 233565 },
+]
+
+[package.optional-dependencies]
+tz = [
+    { name = "tzdata" },
 ]
 
 [[package]]
@@ -83,7 +83,7 @@ source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "idna" },
     { name = "sniffio" },
-    { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+    { name = "typing-extensions" },
 ]
 sdist = { url = "https://files.pythonhosted.org/packages/f6/40/318e58f669b1a9e00f5c4453910682e2d9dd594334539c7b7817dabb765f/anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48", size = 177076 }
 wheels = [
@@ -125,7 +125,7 @@ wheels = [
 
 [[package]]
 name = "astropy"
-version = "7.0.0"
+version = "7.0.1"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "astropy-iers-data" },
@@ -134,38 +134,31 @@ dependencies = [
     { name = "pyerfa" },
     { name = "pyyaml" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/6a/12/d6ad68d5acd751e3827d54a64333e0dd789bcc747fe9528f5758b35421f8/astropy-7.0.0.tar.gz", hash = "sha256:e92d7c9fee86eb3df8714e5dd41bbf9f163d343e1a183d95bf6bd09e4313c940", size = 7130087 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/d6/54/de05566563bb3327d7878cec81507ad5677801f5739eb7623dffef6f6a39/astropy-7.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ada206f13b1e9c9c07ae0fce55e3090d694c555107c23c30b271a58fea1732b", size = 6664940 },
-    { url = "https://files.pythonhosted.org/packages/e3/b4/308bcffcde4c971245f75a8805a6b7606d150090ff9e94317b818808e0ca/astropy-7.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5f5657a1443421b0ab8ae6afa85fc7934f5e384648b7acef21aca5918acfca8", size = 6540264 },
-    { url = "https://files.pythonhosted.org/packages/79/3d/54c4c3773d10f8a6010ab60619c0b0a39c058d2f58abacb3895fac461478/astropy-7.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b47d7af967e51dc612fd8440ed65ad371c0c2bbf5d739ef4aa147bcd2fbe6b13", size = 10605227 },
-    { url = "https://files.pythonhosted.org/packages/34/4c/ec389497ae4305dce4a35062b2851065c535d792f91231f5c290b5c25725/astropy-7.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74c6df5c68cc4acb86e343db6d4b96419d585c7ba5fd41fe3023f47ee9f5dbc9", size = 10663688 },
-    { url = "https://files.pythonhosted.org/packages/21/90/3e2563e37df91c36b1e8e03d2ef49561b6eeb86abac39ee8f66fcf652fb5/astropy-7.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9fcfb92043994dfbd1a267b893398aab8f680b0587b4333dacbfa034a3159aa0", size = 10696004 },
-    { url = "https://files.pythonhosted.org/packages/51/52/a1a5d365d34c6b933db759960fa7451ae3f076e9d020dfa9c5b6fa8dd359/astropy-7.0.0-cp311-cp311-win32.whl", hash = "sha256:1ad4483712effdd691c085e7b58805c01a54cebf8f4c6955973ceccd60bd36ed", size = 6391060 },
-    { url = "https://files.pythonhosted.org/packages/38/76/c7165f1729c98273c9af6a756e0c1f95893b7ff7eea939cb9a72e2699c0f/astropy-7.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:f8a00fcb30c2317b111d8b6a99eb60a81e8292c24dce65e986ee4610ea16b8d2", size = 6522031 },
-    { url = "https://files.pythonhosted.org/packages/83/cf/3356a9b3428b37a895c9f23b6a844814a18dd486e1d3358925bf6222d3eb/astropy-7.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b103516dd54a90f9b9652dff3dd47ad6d43436c61ed800023943a562b7ea9712", size = 6669091 },
-    { url = "https://files.pythonhosted.org/packages/1c/08/e6d55b98514720e6d574647385570e9602414c49c1b6b48903c3cec9415a/astropy-7.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3ced126597ea2d2876a341821d76ba20fb895c2eef117b447b6b3182993794df", size = 6545597 },
-    { url = "https://files.pythonhosted.org/packages/96/d2/a64c3ca06b010cb228f78d9ffc0a41b0c26bcfe7323b60a41f66cfb534b6/astropy-7.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:733be30f52e7ed5ace7fc5ab9bbfbf1f2f604661682141f177ea356893b58cc4", size = 10646328 },
-    { url = "https://files.pythonhosted.org/packages/01/5f/aa4c1a6b1769b0a48d289b9293aaf92b51f190d2ef5da3b4a2090411010d/astropy-7.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14bb14bce6e7cc41066037d8a168b26a5fe6722a9201e9fae8da22a4c34c8780", size = 10728865 },
-    { url = "https://files.pythonhosted.org/packages/01/76/79f2fcf90800d98abfb37928589f54fdf06621d029e2ba6093661c6951d4/astropy-7.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5c14ca39b607af23273ee2b86cecee782a4feb4220b8f7a93b1dc3fe07582779", size = 10741642 },
-    { url = "https://files.pythonhosted.org/packages/e6/75/eae5d114fed94248e1ff83eb798aeb3c67f985bbbdf1312ee690dc723ae4/astropy-7.0.0-cp312-cp312-win32.whl", hash = "sha256:6f2ee5872b0fffd8b9c4d9ce9af51c69f24cdad0d2f4fffbabfcfd4debd303f8", size = 6390205 },
-    { url = "https://files.pythonhosted.org/packages/0a/f6/627fe5592c1f903f8d8d707486e30e2d13eda3fe3e903bd4e35eba5e1b5c/astropy-7.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:62d62d3603bb8b243f6bac21f02341f963418ccf6f299be1d45d8c3918e64c91", size = 6520322 },
-    { url = "https://files.pythonhosted.org/packages/47/1d/6c02cc24248897f07cc417c8583f0c1ae4a80d50f6b45b2e889f331b511c/astropy-7.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e5adeb8f955242da5cb4fe58df2f1483d81c10b2b73f089c91fc87dd3b63e1e", size = 6660947 },
-    { url = "https://files.pythonhosted.org/packages/85/66/bbb28b73eaa4469be1be88e302f133f3ff2b3b295f80ca4bc6e10269973e/astropy-7.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:31614b6451436163eed3744b90edd89dd357bf223c482fa944e627be86a47349", size = 6537491 },
-    { url = "https://files.pythonhosted.org/packages/1e/5f/9cfd728e903972f0bcf6f0048f813d225e67447cab01889571fd25a060a0/astropy-7.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7b28a144165e4e7f4f0467fb6d8ed079f320fc99969a907614d98b18c7cea99", size = 10547602 },
-    { url = "https://files.pythonhosted.org/packages/bd/0c/11e0cd93a8235627e154aeda1cf083e8bebd0ff72a27fea3390d2b2df1c2/astropy-7.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db36b632989060ce4f7c3058ffc860af38df5c8ee7ee7ef2daad1f441c416c12", size = 10635466 },
-    { url = "https://files.pythonhosted.org/packages/de/25/19f515e7f7ad4800b1bc4d642f40f7872b39476c1d8e9ab690b7e702bf30/astropy-7.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c6a14810e596b9d437fbfe40733d61afccc9d4b7b9f7504228ba492f545d197f", size = 10652309 },
-    { url = "https://files.pythonhosted.org/packages/17/02/be4a0d3f6add53c3ebfbf7d4f2704030ea04f06963abb0a9286528a8ab27/astropy-7.0.0-cp313-cp313-win32.whl", hash = "sha256:446931f9c260294ddc8646684ab2413e1a5eb14dcd4ff1e8a0532fa143b0844e", size = 6387551 },
-    { url = "https://files.pythonhosted.org/packages/fa/3a/cf06361685f72b50b3fb69247b95b66a6d2edb1b1947e6403c168f01eecc/astropy-7.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:7ecaaeeb017cceb02512d5505c43e162b3e26d951cece2b021e786f4c0af17a7", size = 6516991 },
+sdist = { url = "https://files.pythonhosted.org/packages/45/12/a1c582b3f9df5e2680eae0ed82c8057ae06d6130a1f7a5c0770fa899737e/astropy-7.0.1.tar.gz", hash = "sha256:392feeb443b2437cd4c2e0641a65e0f15ba791e148e9b1e5ed7de7dfcb38e460", size = 7139539 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/d0/79/ab4edcdb5928ed636b24d6e721460880d0bb6a7a2bca228d06abb5d2a5e4/astropy-7.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b16c5e3cd30ecedc79401a931eaeae3b9f2fc17f19ea26693c6c424cda74bd0e", size = 6574981 },
+    { url = "https://files.pythonhosted.org/packages/57/34/87a0feca0214f21092c75381b046b9eb71cf56ea406f6148aa34cf30c3bb/astropy-7.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11c680207674a53afd603addf5640809bb670f72e9f9a6f023b862040ba7e100", size = 6499230 },
+    { url = "https://files.pythonhosted.org/packages/4e/08/e112c26a69ce00238d3d03b5d200d86816b9db5b582169957a9102416aae/astropy-7.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e930aa618a1df80ecc38ecc594ca1e7508909c79c4b1145e9e91e8695fd163c", size = 10251470 },
+    { url = "https://files.pythonhosted.org/packages/75/9d/1e150830a5491b684e2bb8c8e7224702ac57c101b4e208ed8f84eeedbf5a/astropy-7.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b4831c5b8a8e6c62afc095d9f65e6c023f058821c1fcc829adc2d941090cd2a", size = 10310513 },
+    { url = "https://files.pythonhosted.org/packages/5c/f0/2c4cd9fbbdb222aaafe902fe39e62851ab8fe25b394f328d68df0d0f2301/astropy-7.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2245f23020db2382f187a880dd903f1d4747cbdce6af8f299bc6d4f256b382bf", size = 10345694 },
+    { url = "https://files.pythonhosted.org/packages/5a/0c/f0c7624e0db2b81ff7e2bb8fbf3c0403c9f4e9ed29a99132af51d26b54b6/astropy-7.0.1-cp311-cp311-win32.whl", hash = "sha256:91bec2ac62f759300279fd98f3baf2fe33082729045d80c231948d6df0cceacc", size = 6364686 },
+    { url = "https://files.pythonhosted.org/packages/65/61/b85c917adbd0a69ebe0e512285abea1ae81e1a713ae55452b4f20afdb1e7/astropy-7.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:0ae8960fe690f62672afff723d5e7d25ccd054c941c3ded96471d4d62563864e", size = 6489635 },
+    { url = "https://files.pythonhosted.org/packages/74/e2/3dc27026a098171cf3f88d964dfdf39c70c75fd205624f2f9be8381268f7/astropy-7.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b075f4b8034a3e40d417c079232f1adb613a40e3b8d7cebdb05278666bfeb3ca", size = 6581263 },
+    { url = "https://files.pythonhosted.org/packages/2d/45/0ae6513fc819a9223c5a779b2955ceb27ab5ad57c44e16abcc9fbaee838c/astropy-7.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:71bb61871859635653e0530ca152c379882473ff4aabf2484a848ead94efe248", size = 6504874 },
+    { url = "https://files.pythonhosted.org/packages/ae/f8/2d151d9476eb8797923164aee9764873c28be3654c7c60eae5d33f916d30/astropy-7.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1692857a3f21cecadefe89e4371e9c5a2d03e80173f4bb01dcbe3e3213ad1303", size = 10279377 },
+    { url = "https://files.pythonhosted.org/packages/ed/70/930a24bd3f2046ba2c4b8a914d0349ffb17760d044f2a4e8c3195b984851/astropy-7.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062f9dc6549884699c551310a21434ff650c9a1cb6c0eea9476ead456f8a8500", size = 10358814 },
+    { url = "https://files.pythonhosted.org/packages/22/07/28bc41436ada5e614a583371780d03f6377aa845450d0b04d544dee5c49c/astropy-7.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9cd02ef44007e0d6f27f0136410253a64b1ae56a2333c7071fd775c6feea8e12", size = 10377323 },
+    { url = "https://files.pythonhosted.org/packages/4e/56/175acf7145af6c77cfeca339837293b2dee06936280bf841b6df8da30c92/astropy-7.0.1-cp312-cp312-win32.whl", hash = "sha256:ba9c09cb1ba9c126b40cbbbe9273b4e6f2b0403d268f64a15ed976f77754372b", size = 6364259 },
+    { url = "https://files.pythonhosted.org/packages/69/a8/ae5bb7849274b04248817fc8c885c0966c02c7d20a9a7f9e7388fa9f091f/astropy-7.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:02259457097a3bad3e50975d67bd7586753b2a69d680f071be5c8da439e0f2c4", size = 6489380 },
 ]
 
 [[package]]
 name = "astropy-iers-data"
-version = "0.2025.1.6.0.33.42"
+version = "0.2025.2.17.0.34.13"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/7d/8a/de7f87e461ba32901e0b212c8331d1476e7744f17828bf12ecaf9fdb396d/astropy_iers_data-0.2025.1.6.0.33.42.tar.gz", hash = "sha256:0c7e61bcadbafa7db073074eb5f90754449fab65e59abbbc9a65004b5eb4e763", size = 1888427 }
+sdist = { url = "https://files.pythonhosted.org/packages/90/8f/5b84d3b0cb98708d5bb8b4f1442ca9bdfd3dc1ffd4a1cde715e714e3ff85/astropy_iers_data-0.2025.2.17.0.34.13.tar.gz", hash = "sha256:34b685447a32e63f43811adcee2588bcd55dd77dfc454a05c25f0bbf80066960", size = 1893113 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/55/59/95b2bd9c63a8574e60d2352e2935ff8790a3acedef4288fb190a6456734c/astropy_iers_data-0.2025.1.6.0.33.42-py3-none-any.whl", hash = "sha256:32fb70d788e200f70cba1e44f0b1798a51836ac586920bd168e73ec312aae773", size = 1941331 },
+    { url = "https://files.pythonhosted.org/packages/f2/e2/496d0136d7b1446ad2cfcd4aacae8220301d9789400a916da8d79019c487/astropy_iers_data-0.2025.2.17.0.34.13-py3-none-any.whl", hash = "sha256:2024e3251e1360cdbd978ccf19152610396d2324f5b2af19746e903e243b7566", size = 1945936 },
 ]
 
 [[package]]
@@ -199,23 +192,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/c8/e7/3693392d3e168ab0aebb2d361431375bd22ffc7b4a586a0fc060d519fae7/asyncpg-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:db9891e2d76e6f425746c5d2da01921e9a16b5a71a1c905b13f30e12a257c4af", size = 3641632 },
     { url = "https://files.pythonhosted.org/packages/32/ea/15670cea95745bba3f0352341db55f506a820b21c619ee66b7d12ea7867d/asyncpg-0.30.0-cp312-cp312-win32.whl", hash = "sha256:68d71a1be3d83d0570049cd1654a9bdfe506e794ecc98ad0873304a9f35e411e", size = 560186 },
     { url = "https://files.pythonhosted.org/packages/7e/6b/fe1fad5cee79ca5f5c27aed7bd95baee529c1bf8a387435c8ba4fe53d5c1/asyncpg-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:9a0292c6af5c500523949155ec17b7fe01a00ace33b68a476d6b5059f9630305", size = 621064 },
-    { url = "https://files.pythonhosted.org/packages/3a/22/e20602e1218dc07692acf70d5b902be820168d6282e69ef0d3cb920dc36f/asyncpg-0.30.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05b185ebb8083c8568ea8a40e896d5f7af4b8554b64d7719c0eaa1eb5a5c3a70", size = 670373 },
-    { url = "https://files.pythonhosted.org/packages/3d/b3/0cf269a9d647852a95c06eb00b815d0b95a4eb4b55aa2d6ba680971733b9/asyncpg-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c47806b1a8cbb0a0db896f4cd34d89942effe353a5035c62734ab13b9f938da3", size = 634745 },
-    { url = "https://files.pythonhosted.org/packages/8e/6d/a4f31bf358ce8491d2a31bfe0d7bcf25269e80481e49de4d8616c4295a34/asyncpg-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b6fde867a74e8c76c71e2f64f80c64c0f3163e687f1763cfaf21633ec24ec33", size = 3512103 },
-    { url = "https://files.pythonhosted.org/packages/96/19/139227a6e67f407b9c386cb594d9628c6c78c9024f26df87c912fabd4368/asyncpg-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46973045b567972128a27d40001124fbc821c87a6cade040cfcd4fa8a30bcdc4", size = 3592471 },
-    { url = "https://files.pythonhosted.org/packages/67/e4/ab3ca38f628f53f0fd28d3ff20edff1c975dd1cb22482e0061916b4b9a74/asyncpg-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9110df111cabc2ed81aad2f35394a00cadf4f2e0635603db6ebbd0fc896f46a4", size = 3496253 },
-    { url = "https://files.pythonhosted.org/packages/ef/5f/0bf65511d4eeac3a1f41c54034a492515a707c6edbc642174ae79034d3ba/asyncpg-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04ff0785ae7eed6cc138e73fc67b8e51d54ee7a3ce9b63666ce55a0bf095f7ba", size = 3662720 },
-    { url = "https://files.pythonhosted.org/packages/e7/31/1513d5a6412b98052c3ed9158d783b1e09d0910f51fbe0e05f56cc370bc4/asyncpg-0.30.0-cp313-cp313-win32.whl", hash = "sha256:ae374585f51c2b444510cdf3595b97ece4f233fde739aa14b50e0d64e8a7a590", size = 560404 },
-    { url = "https://files.pythonhosted.org/packages/c8/a4/cec76b3389c4c5ff66301cd100fe88c318563ec8a520e0b2e792b5b84972/asyncpg-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:f59b430b8e27557c3fb9869222559f7417ced18688375825f8f12302c34e915e", size = 621623 },
 ]
 
 [[package]]
 name = "attrs"
-version = "24.3.0"
+version = "25.1.0"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/48/c8/6260f8ccc11f0917360fc0da435c5c9c7504e3db174d5a12a1494887b045/attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", size = 805984 }
+sdist = { url = "https://files.pythonhosted.org/packages/49/7c/fdf464bcc51d23881d110abd74b512a42b3d5d376a55a831b44c603ae17f/attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", size = 810562 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308", size = 63397 },
+    { url = "https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a", size = 63152 },
 ]
 
 [[package]]
@@ -229,30 +214,30 @@ wheels = [
 
 [[package]]
 name = "boto3"
-version = "1.35.93"
+version = "1.36.22"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "botocore" },
     { name = "jmespath" },
     { name = "s3transfer" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/4c/9f/866d602492987854ecbec3d29119738d33b584f38c2e8d4ff26e3bf968e8/boto3-1.35.93.tar.gz", hash = "sha256:2446e819cf4e295833474cdcf2c92bc82718ce537e9ee1f17f7e3d237f60e69b", size = 110970 }
+sdist = { url = "https://files.pythonhosted.org/packages/50/d0/4b0f04a8704cc303645e8c8f2f701ae01d802e73e755720a7e8be515736e/boto3-1.36.22.tar.gz", hash = "sha256:768c8a4d4a6227fe2258105efa086f1424cba5ca915a5eb2305b2cd979306ad1", size = 111038 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/69/1b/3a9cea35775be34f260bb10ce9d821ea87d09d5738010d401feb39b97f74/boto3-1.35.93-py3-none-any.whl", hash = "sha256:7de2c44c960e486f3c57e5203ea6393c6c4f0914c5f81c789ceb8b5d2ba5d1c5", size = 139178 },
+    { url = "https://files.pythonhosted.org/packages/82/85/623948857076415334a85abcfaf05ad53856403129cc827c4990d82f0463/boto3-1.36.22-py3-none-any.whl", hash = "sha256:39957eabdce009353d72d131046489fbbfa15891865d5f069f1e8bfa414e6b81", size = 139177 },
 ]
 
 [[package]]
 name = "botocore"
-version = "1.35.93"
+version = "1.36.22"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "jmespath" },
     { name = "python-dateutil" },
     { name = "urllib3" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/d7/4f/95d69a973620d2e9377e5dca0a5ffe0c0767e3a6764161ca995e2bab1636/botocore-1.35.93.tar.gz", hash = "sha256:b8d245a01e7d64c41edcf75a42be158df57b9518a83a3dbf5c7e4b8c2bc540cc", size = 13496923 }
+sdist = { url = "https://files.pythonhosted.org/packages/a6/88/0b5d5674d26ae43f0115cad6bd8e0c2b4da7ac5b14352e52c682702863c5/botocore-1.36.22.tar.gz", hash = "sha256:59520247d5a479731724f97c995d5a1c2aae3b303b324f39d99efcfad1d3019e", size = 13570251 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/93/02/ae434045c9eabb0df01610f5feca18fc7afc86b3d061eb47123935a873cb/botocore-1.35.93-py3-none-any.whl", hash = "sha256:47f7161000af6036f806449e3de12acdd3ec11aac7f5578e43e96241413a0f8f", size = 13300724 },
+    { url = "https://files.pythonhosted.org/packages/ec/73/415c9465e124c673454335199b7a6a0ae5e660d8a3d1218706da572427aa/botocore-1.36.22-py3-none-any.whl", hash = "sha256:75d6b34acb0686ee4d54ff6eb285e78ccfe318407428769d1e3e13351714d890", size = 13355109 },
 ]
 
 [[package]]
@@ -266,11 +251,11 @@ wheels = [
 
 [[package]]
 name = "certifi"
-version = "2024.12.14"
+version = "2025.1.31"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/0f/bd/1d41ee578ce09523c81a15426705dd20969f5abf006d1afe8aeff0dd776a/certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db", size = 166010 }
+sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927 },
+    { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 },
 ]
 
 [[package]]
@@ -305,17 +290,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 },
     { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 },
     { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 },
-    { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 },
-    { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 },
-    { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 },
-    { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 },
-    { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 },
-    { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 },
-    { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 },
-    { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 },
-    { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 },
-    { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 },
-    { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 },
 ]
 
 [[package]]
@@ -359,19 +333,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 },
     { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 },
     { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 },
-    { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 },
-    { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 },
-    { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 },
-    { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 },
-    { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 },
-    { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 },
-    { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 },
-    { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 },
-    { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 },
-    { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 },
-    { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 },
-    { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 },
-    { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 },
     { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 },
 ]
 
@@ -380,7 +341,7 @@ name = "click"
 version = "8.1.8"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "colorama", marker = "platform_system == 'Windows'" },
+    { name = "colorama", marker = "sys_platform == 'win32'" },
 ]
 sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
 wheels = [
@@ -410,50 +371,31 @@ wheels = [
 
 [[package]]
 name = "coverage"
-version = "7.6.10"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/84/ba/ac14d281f80aab516275012e8875991bb06203957aa1e19950139238d658/coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23", size = 803868 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/85/d2/5e175fcf6766cf7501a8541d81778fd2f52f4870100e791f5327fd23270b/coverage-7.6.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3", size = 208088 },
-    { url = "https://files.pythonhosted.org/packages/4b/6f/06db4dc8fca33c13b673986e20e466fd936235a6ec1f0045c3853ac1b593/coverage-7.6.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43", size = 208536 },
-    { url = "https://files.pythonhosted.org/packages/0d/62/c6a0cf80318c1c1af376d52df444da3608eafc913b82c84a4600d8349472/coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132", size = 240474 },
-    { url = "https://files.pythonhosted.org/packages/a3/59/750adafc2e57786d2e8739a46b680d4fb0fbc2d57fbcb161290a9f1ecf23/coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f", size = 237880 },
-    { url = "https://files.pythonhosted.org/packages/2c/f8/ef009b3b98e9f7033c19deb40d629354aab1d8b2d7f9cfec284dbedf5096/coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994", size = 239750 },
-    { url = "https://files.pythonhosted.org/packages/a6/e2/6622f3b70f5f5b59f705e680dae6db64421af05a5d1e389afd24dae62e5b/coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99", size = 238642 },
-    { url = "https://files.pythonhosted.org/packages/2d/10/57ac3f191a3c95c67844099514ff44e6e19b2915cd1c22269fb27f9b17b6/coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd", size = 237266 },
-    { url = "https://files.pythonhosted.org/packages/ee/2d/7016f4ad9d553cabcb7333ed78ff9d27248ec4eba8dd21fa488254dff894/coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377", size = 238045 },
-    { url = "https://files.pythonhosted.org/packages/a7/fe/45af5c82389a71e0cae4546413266d2195c3744849669b0bab4b5f2c75da/coverage-7.6.10-cp311-cp311-win32.whl", hash = "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8", size = 210647 },
-    { url = "https://files.pythonhosted.org/packages/db/11/3f8e803a43b79bc534c6a506674da9d614e990e37118b4506faf70d46ed6/coverage-7.6.10-cp311-cp311-win_amd64.whl", hash = "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609", size = 211508 },
-    { url = "https://files.pythonhosted.org/packages/86/77/19d09ea06f92fdf0487499283b1b7af06bc422ea94534c8fe3a4cd023641/coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853", size = 208281 },
-    { url = "https://files.pythonhosted.org/packages/b6/67/5479b9f2f99fcfb49c0d5cf61912a5255ef80b6e80a3cddba39c38146cf4/coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078", size = 208514 },
-    { url = "https://files.pythonhosted.org/packages/15/d1/febf59030ce1c83b7331c3546d7317e5120c5966471727aa7ac157729c4b/coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0", size = 241537 },
-    { url = "https://files.pythonhosted.org/packages/4b/7e/5ac4c90192130e7cf8b63153fe620c8bfd9068f89a6d9b5f26f1550f7a26/coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50", size = 238572 },
-    { url = "https://files.pythonhosted.org/packages/dc/03/0334a79b26ecf59958f2fe9dd1f5ab3e2f88db876f5071933de39af09647/coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022", size = 240639 },
-    { url = "https://files.pythonhosted.org/packages/d7/45/8a707f23c202208d7b286d78ad6233f50dcf929319b664b6cc18a03c1aae/coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b", size = 240072 },
-    { url = "https://files.pythonhosted.org/packages/66/02/603ce0ac2d02bc7b393279ef618940b4a0535b0868ee791140bda9ecfa40/coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0", size = 238386 },
-    { url = "https://files.pythonhosted.org/packages/04/62/4e6887e9be060f5d18f1dd58c2838b2d9646faf353232dec4e2d4b1c8644/coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852", size = 240054 },
-    { url = "https://files.pythonhosted.org/packages/5c/74/83ae4151c170d8bd071924f212add22a0e62a7fe2b149edf016aeecad17c/coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359", size = 210904 },
-    { url = "https://files.pythonhosted.org/packages/c3/54/de0893186a221478f5880283119fc40483bc460b27c4c71d1b8bba3474b9/coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247", size = 211692 },
-    { url = "https://files.pythonhosted.org/packages/25/6d/31883d78865529257bf847df5789e2ae80e99de8a460c3453dbfbe0db069/coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9", size = 208308 },
-    { url = "https://files.pythonhosted.org/packages/70/22/3f2b129cc08de00c83b0ad6252e034320946abfc3e4235c009e57cfeee05/coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b", size = 208565 },
-    { url = "https://files.pythonhosted.org/packages/97/0a/d89bc2d1cc61d3a8dfe9e9d75217b2be85f6c73ebf1b9e3c2f4e797f4531/coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690", size = 241083 },
-    { url = "https://files.pythonhosted.org/packages/4c/81/6d64b88a00c7a7aaed3a657b8eaa0931f37a6395fcef61e53ff742b49c97/coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18", size = 238235 },
-    { url = "https://files.pythonhosted.org/packages/9a/0b/7797d4193f5adb4b837207ed87fecf5fc38f7cc612b369a8e8e12d9fa114/coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c", size = 240220 },
-    { url = "https://files.pythonhosted.org/packages/65/4d/6f83ca1bddcf8e51bf8ff71572f39a1c73c34cf50e752a952c34f24d0a60/coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd", size = 239847 },
-    { url = "https://files.pythonhosted.org/packages/30/9d/2470df6aa146aff4c65fee0f87f58d2164a67533c771c9cc12ffcdb865d5/coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e", size = 237922 },
-    { url = "https://files.pythonhosted.org/packages/08/dd/723fef5d901e6a89f2507094db66c091449c8ba03272861eaefa773ad95c/coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694", size = 239783 },
-    { url = "https://files.pythonhosted.org/packages/3d/f7/64d3298b2baf261cb35466000628706ce20a82d42faf9b771af447cd2b76/coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6", size = 210965 },
-    { url = "https://files.pythonhosted.org/packages/d5/58/ec43499a7fc681212fe7742fe90b2bc361cdb72e3181ace1604247a5b24d/coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e", size = 211719 },
-    { url = "https://files.pythonhosted.org/packages/ab/c9/f2857a135bcff4330c1e90e7d03446b036b2363d4ad37eb5e3a47bbac8a6/coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe", size = 209050 },
-    { url = "https://files.pythonhosted.org/packages/aa/b3/f840e5bd777d8433caa9e4a1eb20503495709f697341ac1a8ee6a3c906ad/coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273", size = 209321 },
-    { url = "https://files.pythonhosted.org/packages/85/7d/125a5362180fcc1c03d91850fc020f3831d5cda09319522bcfa6b2b70be7/coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8", size = 252039 },
-    { url = "https://files.pythonhosted.org/packages/a9/9c/4358bf3c74baf1f9bddd2baf3756b54c07f2cfd2535f0a47f1e7757e54b3/coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098", size = 247758 },
-    { url = "https://files.pythonhosted.org/packages/cf/c7/de3eb6fc5263b26fab5cda3de7a0f80e317597a4bad4781859f72885f300/coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb", size = 250119 },
-    { url = "https://files.pythonhosted.org/packages/3e/e6/43de91f8ba2ec9140c6a4af1102141712949903dc732cf739167cfa7a3bc/coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0", size = 249597 },
-    { url = "https://files.pythonhosted.org/packages/08/40/61158b5499aa2adf9e37bc6d0117e8f6788625b283d51e7e0c53cf340530/coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf", size = 247473 },
-    { url = "https://files.pythonhosted.org/packages/50/69/b3f2416725621e9f112e74e8470793d5b5995f146f596f133678a633b77e/coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2", size = 248737 },
-    { url = "https://files.pythonhosted.org/packages/3c/6e/fe899fb937657db6df31cc3e61c6968cb56d36d7326361847440a430152e/coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312", size = 211611 },
-    { url = "https://files.pythonhosted.org/packages/1c/55/52f5e66142a9d7bc93a15192eba7a78513d2abf6b3558d77b4ca32f5f424/coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d", size = 212781 },
+version = "7.6.12"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/0c/d6/2b53ab3ee99f2262e6f0b8369a43f6d66658eab45510331c0b3d5c8c4272/coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2", size = 805941 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/64/2d/da78abbfff98468c91fd63a73cccdfa0e99051676ded8dd36123e3a2d4d5/coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015", size = 208464 },
+    { url = "https://files.pythonhosted.org/packages/31/f2/c269f46c470bdabe83a69e860c80a82e5e76840e9f4bbd7f38f8cebbee2f/coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45", size = 208893 },
+    { url = "https://files.pythonhosted.org/packages/47/63/5682bf14d2ce20819998a49c0deadb81e608a59eed64d6bc2191bc8046b9/coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702", size = 241545 },
+    { url = "https://files.pythonhosted.org/packages/6a/b6/6b6631f1172d437e11067e1c2edfdb7238b65dff965a12bce3b6d1bf2be2/coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0", size = 239230 },
+    { url = "https://files.pythonhosted.org/packages/c7/01/9cd06cbb1be53e837e16f1b4309f6357e2dfcbdab0dd7cd3b1a50589e4e1/coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f", size = 241013 },
+    { url = "https://files.pythonhosted.org/packages/4b/26/56afefc03c30871326e3d99709a70d327ac1f33da383cba108c79bd71563/coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f", size = 239750 },
+    { url = "https://files.pythonhosted.org/packages/dd/ea/88a1ff951ed288f56aa561558ebe380107cf9132facd0b50bced63ba7238/coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d", size = 238462 },
+    { url = "https://files.pythonhosted.org/packages/6e/d4/1d9404566f553728889409eff82151d515fbb46dc92cbd13b5337fa0de8c/coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba", size = 239307 },
+    { url = "https://files.pythonhosted.org/packages/12/c1/e453d3b794cde1e232ee8ac1d194fde8e2ba329c18bbf1b93f6f5eef606b/coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f", size = 211117 },
+    { url = "https://files.pythonhosted.org/packages/d5/db/829185120c1686fa297294f8fcd23e0422f71070bf85ef1cc1a72ecb2930/coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558", size = 212019 },
+    { url = "https://files.pythonhosted.org/packages/e2/7f/4af2ed1d06ce6bee7eafc03b2ef748b14132b0bdae04388e451e4b2c529b/coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad", size = 208645 },
+    { url = "https://files.pythonhosted.org/packages/dc/60/d19df912989117caa95123524d26fc973f56dc14aecdec5ccd7d0084e131/coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3", size = 208898 },
+    { url = "https://files.pythonhosted.org/packages/bd/10/fecabcf438ba676f706bf90186ccf6ff9f6158cc494286965c76e58742fa/coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574", size = 242987 },
+    { url = "https://files.pythonhosted.org/packages/4c/53/4e208440389e8ea936f5f2b0762dcd4cb03281a7722def8e2bf9dc9c3d68/coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985", size = 239881 },
+    { url = "https://files.pythonhosted.org/packages/c4/47/2ba744af8d2f0caa1f17e7746147e34dfc5f811fb65fc153153722d58835/coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750", size = 242142 },
+    { url = "https://files.pythonhosted.org/packages/e9/90/df726af8ee74d92ee7e3bf113bf101ea4315d71508952bd21abc3fae471e/coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea", size = 241437 },
+    { url = "https://files.pythonhosted.org/packages/f6/af/995263fd04ae5f9cf12521150295bf03b6ba940d0aea97953bb4a6db3e2b/coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3", size = 239724 },
+    { url = "https://files.pythonhosted.org/packages/1c/8e/5bb04f0318805e190984c6ce106b4c3968a9562a400180e549855d8211bd/coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a", size = 241329 },
+    { url = "https://files.pythonhosted.org/packages/9e/9d/fa04d9e6c3f6459f4e0b231925277cfc33d72dfab7fa19c312c03e59da99/coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95", size = 211289 },
+    { url = "https://files.pythonhosted.org/packages/53/40/53c7ffe3c0c3fff4d708bc99e65f3d78c129110d6629736faf2dbd60ad57/coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288", size = 212079 },
+    { url = "https://files.pythonhosted.org/packages/fb/b2/f655700e1024dec98b10ebaafd0cedbc25e40e4abe62a3c8e2ceef4f8f0a/coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953", size = 200552 },
 ]
 
 [package.optional-dependencies]
@@ -492,15 +434,16 @@ wheels = [
 
 [[package]]
 name = "dacite"
-version = "1.8.1"
+version = "1.9.2"
 source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/55/a0/7ca79796e799a3e782045d29bf052b5cde7439a2bbb17f15ff44f7aacc63/dacite-1.9.2.tar.gz", hash = "sha256:6ccc3b299727c7aa17582f0021f6ae14d5de47c7227932c47fec4cdfefd26f09", size = 22420 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/21/0f/cf0943f4f55f0fbc7c6bd60caf1343061dff818b02af5a0d444e473bb78d/dacite-1.8.1-py3-none-any.whl", hash = "sha256:cc31ad6fdea1f49962ea42db9421772afe01ac5442380d9a99fcf3d188c61afe", size = 14309 },
+    { url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600 },
 ]
 
 [[package]]
 name = "dataclasses-avroschema"
-version = "0.65.7"
+version = "0.65.8"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "casefy" },
@@ -510,9 +453,9 @@ dependencies = [
     { name = "python-dateutil" },
     { name = "typing-extensions" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/6a/77/7b6eb611e8e1aadc5193ef16ba97a0d803e6d2b7a09b6965375eea4e7b3b/dataclasses_avroschema-0.65.7.tar.gz", hash = "sha256:62b874f020b57294f65e7aced4a634757502e1b410bdb1d6f8e0515eb3fc5c3e", size = 46079 }
+sdist = { url = "https://files.pythonhosted.org/packages/f7/f7/a40dee4acb92e6263416ff58c464e0f2c260e7aa2a0c9ae948a1ef5f17e3/dataclasses_avroschema-0.65.8.tar.gz", hash = "sha256:6b5393c68a29eabe0a6bc652eae8e3a21de65f3231637da1f8a52553ef77fb20", size = 44788 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/7b/cb/710306f2e8f769ca5913b51d5988a0940affc1a1be08be21dc69de366a35/dataclasses_avroschema-0.65.7-py3-none-any.whl", hash = "sha256:e59a8a962e1956533a9083468a08dd3958553738e3f87f6bc516fe525901302f", size = 57937 },
+    { url = "https://files.pythonhosted.org/packages/00/7c/7e2502cebd778de40cc5dcb969a48e25b43ceed441bfa58d25ac4014c19b/dataclasses_avroschema-0.65.8-py3-none-any.whl", hash = "sha256:3d1202756692fabf2f59862eaeab95367b4c444dfaff64ae21091362b5c2d60c", size = 57972 },
 ]
 
 [[package]]
@@ -526,14 +469,14 @@ wheels = [
 
 [[package]]
 name = "deprecated"
-version = "1.2.15"
+version = "1.2.18"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "wrapt" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/2e/a3/53e7d78a6850ffdd394d7048a31a6f14e44900adedf190f9a165f6b69439/deprecated-1.2.15.tar.gz", hash = "sha256:683e561a90de76239796e6b6feac66b99030d2dd3fcf61ef996330f14bbb9b0d", size = 2977612 }
+sdist = { url = "https://files.pythonhosted.org/packages/98/97/06afe62762c9a8a86af0cfb7bfdab22a43ad17138b07af5b1a58442690a2/deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d", size = 2928744 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/1d/8f/c7f227eb42cfeaddce3eb0c96c60cbca37797fa7b34f8e1aeadf6c5c0983/Deprecated-1.2.15-py2.py3-none-any.whl", hash = "sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320", size = 9941 },
+    { url = "https://files.pythonhosted.org/packages/6e/c6/ac0b6c1e2d138f1002bcf799d330bd6d85084fece321e662a14223794041/Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec", size = 9998 },
 ]
 
 [[package]]
@@ -553,15 +496,15 @@ sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf57
 
 [[package]]
 name = "dogpile-cache"
-version = "1.3.3"
+version = "1.3.4"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "decorator" },
     { name = "stevedore" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/81/3b/83ce66995ce658ad63b86f7ca83943c466133108f20edc7056d4e0f41347/dogpile.cache-1.3.3.tar.gz", hash = "sha256:f84b8ed0b0fb297d151055447fa8dcaf7bae566d4dbdefecdcc1f37662ab588b", size = 272404 }
+sdist = { url = "https://files.pythonhosted.org/packages/cb/b7/2fa37f52b4f38bc8eb6d4923163dd822ca6f9e2f817378478a5de73b239e/dogpile_cache-1.3.4.tar.gz", hash = "sha256:4f0295575f5fdd3f7e13c84ba8e36656971d1869a2081b4737ec99ede378a8c0", size = 933234 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/c9/b6/eb8bb5bced9f0bf475b22a53e86e4ed80fa60949de1133e2e673e23282d7/dogpile.cache-1.3.3-py3-none-any.whl", hash = "sha256:5e211c4902ebdf88c678d268e22454b41e68071632daa9402d8ee24e825ed8ca", size = 58651 },
+    { url = "https://files.pythonhosted.org/packages/3c/82/d118accb66f9048acbc4ff91592755c24d52f54cce40d6b0b2a0ce351cf5/dogpile.cache-1.3.4-py3-none-any.whl", hash = "sha256:a393412f93d24a8942fdf9248dc80678127d54c5e60a7be404027aa193cafe12", size = 62859 },
 ]
 
 [[package]]
@@ -588,16 +531,16 @@ wheels = [
 
 [[package]]
 name = "fastapi"
-version = "0.115.6"
+version = "0.115.8"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "pydantic" },
     { name = "starlette" },
     { name = "typing-extensions" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/93/72/d83b98cd106541e8f5e5bfab8ef2974ab45a62e8a6c5b5e6940f26d2ed4b/fastapi-0.115.6.tar.gz", hash = "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654", size = 301336 }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/b2/5a5dc4affdb6661dea100324e19a7721d5dc524b464fe8e366c093fd7d87/fastapi-0.115.8.tar.gz", hash = "sha256:0ce9111231720190473e222cdf0f07f7206ad7e53ea02beb1d2dc36e2f0741e9", size = 295403 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/52/b3/7e4df40e585df024fac2f80d1a2d579c854ac37109675db2b0cc22c0bb9e/fastapi-0.115.6-py3-none-any.whl", hash = "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305", size = 94843 },
+    { url = "https://files.pythonhosted.org/packages/8f/7d/2d6ce181d7a5f51dedb8c06206cbf0ec026a99bf145edd309f9e17c3282f/fastapi-0.115.8-py3-none-any.whl", hash = "sha256:753a96dd7e036b34eeef8babdfcfe3f28ff79648f86551eb36bfc1b0bf4a8cbf", size = 94814 },
 ]
 
 [[package]]
@@ -618,35 +561,29 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/2e/40/26e56696b9696ab4fbba25a96b8037ca3f9fd8a8cc55b4b36400ef023e49/fastavro-1.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6575be7f2b5f94023b5a4e766b0251924945ad55e9a96672dc523656d17fe251", size = 3258045 },
     { url = "https://files.pythonhosted.org/packages/4e/bc/2f6c92c06c5363372abe828bccdd95762f2c1983b261509f94189c38c8a1/fastavro-1.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe471deb675ed2f01ee2aac958fbf8ebb13ea00fa4ce7f87e57710a0bc592208", size = 3418001 },
     { url = "https://files.pythonhosted.org/packages/0c/ce/cfd16546c04ebbca1be80873b533c788cec76f7bfac231bfac6786047572/fastavro-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:567ff515f2a5d26d9674b31c95477f3e6022ec206124c62169bc2ffaf0889089", size = 487855 },
-    { url = "https://files.pythonhosted.org/packages/c9/c4/163cf154cc694c2dccc70cd6796db6214ac668a1260bf0310401dad188dc/fastavro-1.10.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:82263af0adfddb39c85f9517d736e1e940fe506dfcc35bc9ab9f85e0fa9236d8", size = 1022741 },
-    { url = "https://files.pythonhosted.org/packages/38/01/a24598f5f31b8582a92fe9c41bf91caeed50d5b5eaa7576e6f8b23cb488d/fastavro-1.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:566c193109ff0ff84f1072a165b7106c4f96050078a4e6ac7391f81ca1ef3efa", size = 3237421 },
-    { url = "https://files.pythonhosted.org/packages/a7/bf/08bcf65cfb7feb0e5b1329fafeb4a9b95b7b5ec723ba58c7dbd0d04ded34/fastavro-1.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e400d2e55d068404d9fea7c5021f8b999c6f9d9afa1d1f3652ec92c105ffcbdd", size = 3300222 },
-    { url = "https://files.pythonhosted.org/packages/53/4d/a6c25f3166328f8306ec2e6be1123ed78a55b8ab774a43a661124508881f/fastavro-1.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9b8227497f71565270f9249fc9af32a93644ca683a0167cfe66d203845c3a038", size = 3233276 },
-    { url = "https://files.pythonhosted.org/packages/47/1c/b2b2ce2bf866a248ae23e96a87b3b8369427ff79be9112073039bee1d245/fastavro-1.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8e62d04c65461b30ac6d314e4197ad666371e97ae8cb2c16f971d802f6c7f514", size = 3388936 },
-    { url = "https://files.pythonhosted.org/packages/1f/2c/43927e22a2d57587b3aa09765098a6d833246b672d34c10c5f135414745a/fastavro-1.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:86baf8c9740ab570d0d4d18517da71626fe9be4d1142bea684db52bd5adb078f", size = 483967 },
 ]
 
 [[package]]
 name = "faststream"
-version = "0.5.33"
+version = "0.5.34"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "anyio" },
     { name = "fast-depends" },
     { name = "typing-extensions" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/1a/51/33380ca2877a8b83e94d479b567cf15fe38bb2df0d3cbeb54d07f3b9e694/faststream-0.5.33.tar.gz", hash = "sha256:d40761c9f5db9b2cee69748832c4ead20d61805c439d3fbe3107fe4c9a066b2d", size = 286391 }
+sdist = { url = "https://files.pythonhosted.org/packages/8a/e8/cbfb97a85245c849e77ef628b5fd279b55ad6d94cdab4b2f5cb1d5934123/faststream-0.5.34.tar.gz", hash = "sha256:84615968c5768ebaa89b72ae66b53e5302c08e7d18b341ef5193e54cb6ba8623", size = 287921 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/64/db/a4aa303e425bf629523a3c706dd67035cac547a92b3c24504e194cafaf42/faststream-0.5.33-py3-none-any.whl", hash = "sha256:24b3b48dff4195c63141864fae24608c4e3e08c9172faccc74b0c46d6d88f665", size = 385102 },
+    { url = "https://files.pythonhosted.org/packages/b5/36/d20d3e45e95f9cf8d2684cf1cc201e1738e8d4f4ad61a1debeec7ecc646d/faststream-0.5.34-py3-none-any.whl", hash = "sha256:aa7f61d6968a68f13ebf755cce9e8bf11b00717c28b2ef66e896b5d652a6c6a2", size = 386689 },
 ]
 
 [[package]]
 name = "filelock"
-version = "3.16.1"
+version = "3.17.0"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/9d/db/3ef5bb276dae18d6ec2124224403d1d67bccdbefc17af4cc8f553e341ab1/filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435", size = 18037 }
+sdist = { url = "https://files.pythonhosted.org/packages/dc/9c/0b15fb47b464e1b663b1acd1253a062aa5feecb07d4e597daea542ebd2b5/filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e", size = 18027 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163 },
+    { url = "https://files.pythonhosted.org/packages/89/ec/00d68c4ddfedfe64159999e5f8a98fb8442729a63e2077eb9dcd89623d27/filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338", size = 16164 },
 ]
 
 [[package]]
@@ -657,7 +594,6 @@ sdist = { url = "https://files.pythonhosted.org/packages/bb/59/19eb300ba28e75475
 wheels = [
     { url = "https://files.pythonhosted.org/packages/04/13/d9839089b900fa7b479cce495d62110cddc4bd5630a04d8469916c0e79c5/frozendict-2.4.6-py311-none-any.whl", hash = "sha256:d065db6a44db2e2375c23eac816f1a022feb2fa98cbb50df44a9e83700accbea", size = 16148 },
     { url = "https://files.pythonhosted.org/packages/ba/d0/d482c39cee2ab2978a892558cf130681d4574ea208e162da8958b31e9250/frozendict-2.4.6-py312-none-any.whl", hash = "sha256:49344abe90fb75f0f9fdefe6d4ef6d4894e640fadab71f11009d52ad97f370b9", size = 16146 },
-    { url = "https://files.pythonhosted.org/packages/a5/8e/b6bf6a0de482d7d7d7a2aaac8fdc4a4d0bb24a809f5ddd422aa7060eb3d2/frozendict-2.4.6-py313-none-any.whl", hash = "sha256:7134a2bb95d4a16556bb5f2b9736dceb6ea848fa5b6f3f6c2d6dba93b44b4757", size = 16146 },
 ]
 
 [[package]]
@@ -721,22 +657,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/19/c5/36384a06f748044d06bdd8776e231fadf92fc896bd12cb1c9f5a1bda9578/greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0", size = 1135975 },
     { url = "https://files.pythonhosted.org/packages/38/f9/c0a0eb61bdf808d23266ecf1d63309f0e1471f284300ce6dac0ae1231881/greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942", size = 1163955 },
     { url = "https://files.pythonhosted.org/packages/43/21/a5d9df1d21514883333fc86584c07c2b49ba7c602e670b174bd73cfc9c7f/greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01", size = 299655 },
-    { url = "https://files.pythonhosted.org/packages/f3/57/0db4940cd7bb461365ca8d6fd53e68254c9dbbcc2b452e69d0d41f10a85e/greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1", size = 272990 },
-    { url = "https://files.pythonhosted.org/packages/1c/ec/423d113c9f74e5e402e175b157203e9102feeb7088cee844d735b28ef963/greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff", size = 649175 },
-    { url = "https://files.pythonhosted.org/packages/a9/46/ddbd2db9ff209186b7b7c621d1432e2f21714adc988703dbdd0e65155c77/greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a", size = 663425 },
-    { url = "https://files.pythonhosted.org/packages/bc/f9/9c82d6b2b04aa37e38e74f0c429aece5eeb02bab6e3b98e7db89b23d94c6/greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e", size = 657736 },
-    { url = "https://files.pythonhosted.org/packages/d9/42/b87bc2a81e3a62c3de2b0d550bf91a86939442b7ff85abb94eec3fc0e6aa/greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4", size = 660347 },
-    { url = "https://files.pythonhosted.org/packages/37/fa/71599c3fd06336cdc3eac52e6871cfebab4d9d70674a9a9e7a482c318e99/greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e", size = 615583 },
-    { url = "https://files.pythonhosted.org/packages/4e/96/e9ef85de031703ee7a4483489b40cf307f93c1824a02e903106f2ea315fe/greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1", size = 1133039 },
-    { url = "https://files.pythonhosted.org/packages/87/76/b2b6362accd69f2d1889db61a18c94bc743e961e3cab344c2effaa4b4a25/greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c", size = 1160716 },
-    { url = "https://files.pythonhosted.org/packages/1f/1b/54336d876186920e185066d8c3024ad55f21d7cc3683c856127ddb7b13ce/greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761", size = 299490 },
-    { url = "https://files.pythonhosted.org/packages/5f/17/bea55bf36990e1638a2af5ba10c1640273ef20f627962cf97107f1e5d637/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011", size = 643731 },
-    { url = "https://files.pythonhosted.org/packages/78/d2/aa3d2157f9ab742a08e0fd8f77d4699f37c22adfbfeb0c610a186b5f75e0/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13", size = 649304 },
-    { url = "https://files.pythonhosted.org/packages/f1/8e/d0aeffe69e53ccff5a28fa86f07ad1d2d2d6537a9506229431a2a02e2f15/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475", size = 646537 },
-    { url = "https://files.pythonhosted.org/packages/05/79/e15408220bbb989469c8871062c97c6c9136770657ba779711b90870d867/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b", size = 642506 },
-    { url = "https://files.pythonhosted.org/packages/18/87/470e01a940307796f1d25f8167b551a968540fbe0551c0ebb853cb527dd6/greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822", size = 602753 },
-    { url = "https://files.pythonhosted.org/packages/e2/72/576815ba674eddc3c25028238f74d7b8068902b3968cbe456771b166455e/greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01", size = 1122731 },
-    { url = "https://files.pythonhosted.org/packages/ac/38/08cc303ddddc4b3d7c628c3039a61a3aae36c241ed01393d00c2fd663473/greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6", size = 1142112 },
 ]
 
 [[package]]
@@ -811,13 +731,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289 },
     { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779 },
     { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634 },
-    { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214 },
-    { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431 },
-    { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121 },
-    { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805 },
-    { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858 },
-    { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042 },
-    { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682 },
 ]
 
 [[package]]
@@ -838,7 +751,7 @@ wheels = [
 
 [[package]]
 name = "idds-client"
-version = "2.2.12"
+version = "2.2.19"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "argcomplete" },
@@ -849,11 +762,11 @@ dependencies = [
     { name = "tabulate" },
     { name = "urllib3" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/f1/10/7c0bada52178c12f21b9793bf9f60a36369ed6b766d190a2a2c2e9894fb3/idds_client-2.2.12.tar.gz", hash = "sha256:894012c49847337451fc9efa76157d72a8e978470edcda4f9490896227846d8a", size = 19715 }
+sdist = { url = "https://files.pythonhosted.org/packages/33/34/24b8781a26fb4e91caf2c42b1cb7efbcc78a4177254f438e9d22ca5d1a68/idds_client-2.2.19.tar.gz", hash = "sha256:79d3e201fbc4833b43993e33cb08d790cf2844d8dc6dc04f861b51bd79042111", size = 19826 }
 
 [[package]]
 name = "idds-common"
-version = "2.2.12"
+version = "2.2.19"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "dogpile-cache" },
@@ -861,11 +774,11 @@ dependencies = [
     { name = "pip" },
     { name = "requests" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/ee/e9/67bd4222c85e2ab85e9129d54654a069553de4f9ecc45b0b3173c4d385cc/idds_common-2.2.12.tar.gz", hash = "sha256:b069915e793c2edce60a69702b422f694d3c251e3d37e86f930a6fe4f37ddf5d", size = 28209 }
+sdist = { url = "https://files.pythonhosted.org/packages/2b/81/9b0bcd38ae35e5d2c5f3e712eda8ba2c80450b92b7f3b8784a4dbe1e1959/idds_common-2.2.19.tar.gz", hash = "sha256:654ec9246e584b2d537be1c86f3bdb3768176a7a21ffbb6806849a8cb29d82af", size = 28356 }
 
 [[package]]
 name = "idds-doma"
-version = "2.2.12"
+version = "2.2.19"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "idds-common" },
@@ -873,11 +786,11 @@ dependencies = [
     { name = "panda-client-light" },
     { name = "pip" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/dc/d5/84f33ea968fe538b944048331a365de9242aca45cf474434c8be1e29607b/idds_doma-2.2.12.tar.gz", hash = "sha256:4d53fa5bdd13bc06b7fdad76426aa5422dc276aa93d6fff90e718f4a50c5c503", size = 40960 }
+sdist = { url = "https://files.pythonhosted.org/packages/da/3b/32c03306eebe465a7a5d4b67d4a25d5535e65bd06e6d4560d5dcb7d8f8b4/idds_doma-2.2.19.tar.gz", hash = "sha256:58f6580d4b42f3a30a50c548c37e92e9e9867ba266970684da5dff7fba70837d", size = 41162 }
 
 [[package]]
 name = "idds-workflow"
-version = "2.2.12"
+version = "2.2.19"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "anytree" },
@@ -886,15 +799,15 @@ dependencies = [
     { name = "pip" },
     { name = "stomp-py" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/1d/3b/ee419eb92000303c8c3e76b1d0b55cb8827ce1cc27fd7811821f48688fb0/idds_workflow-2.2.12.tar.gz", hash = "sha256:f999aab0e1ddb8665ad2c613388ca02ce72442d3439e9988c6bb860e3fbf4b37", size = 81094 }
+sdist = { url = "https://files.pythonhosted.org/packages/ba/9b/2a9764ac846c311ffad129388f60407fff6aa495ef1e9d59ce4b8bea0554/idds_workflow-2.2.19.tar.gz", hash = "sha256:e36ebb338884b1883c0444d7da59d200d830c1554e8cb0f7cb28b26369f69851", size = 81202 }
 
 [[package]]
 name = "identify"
-version = "2.6.5"
+version = "2.6.7"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/cf/92/69934b9ef3c31ca2470980423fda3d00f0460ddefdf30a67adf7f17e2e00/identify-2.6.5.tar.gz", hash = "sha256:c10b33f250e5bba374fae86fb57f3adcebf1161bce7cdf92031915fd480c13bc", size = 99213 }
+sdist = { url = "https://files.pythonhosted.org/packages/83/d1/524aa3350f78bcd714d148ade6133d67d6b7de2cdbae7d99039c024c9a25/identify-2.6.7.tar.gz", hash = "sha256:3fa266b42eba321ee0b2bb0936a6a6b9e36a1351cbb69055b3082f4193035684", size = 99260 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/ec/fa/dce098f4cdf7621aa8f7b4f919ce545891f489482f0bfa5102f3eca8608b/identify-2.6.5-py2.py3-none-any.whl", hash = "sha256:14181a47091eb75b337af4c23078c9d09225cd4c48929f521f3bf16b09d02566", size = 99078 },
+    { url = "https://files.pythonhosted.org/packages/03/00/1fd4a117c6c93f2dcc5b7edaeaf53ea45332ef966429be566ca16c2beb94/identify-2.6.7-py2.py3-none-any.whl", hash = "sha256:155931cb617a401807b09ecec6635d6c692d180090a1cedca8ef7d58ba5b6aa0", size = 99097 },
 ]
 
 [[package]]
@@ -983,7 +896,6 @@ wheels = [
 
 [[package]]
 name = "lsst-cm-service"
-version = "0.2.0rc1"
 source = { editable = "." }
 dependencies = [
     { name = "alembic" },
@@ -1000,11 +912,11 @@ dependencies = [
     { name = "lsst-daf-butler" },
     { name = "lsst-pipe-base" },
     { name = "numpy" },
-    { name = "pause" },
     { name = "psycopg2-binary" },
     { name = "pydantic" },
     { name = "pydantic-settings" },
     { name = "python-multipart" },
+    { name = "rich" },
     { name = "safir", extra = ["db"] },
     { name = "sqlalchemy", extra = ["asyncio"] },
     { name = "structlog" },
@@ -1049,11 +961,11 @@ requires-dist = [
     { name = "lsst-daf-butler", specifier = ">=28.2024.5000" },
     { name = "lsst-pipe-base", specifier = ">=28.2024.5000" },
     { name = "numpy", specifier = "==2.1.*" },
-    { name = "pause", specifier = "==0.3.*" },
     { name = "psycopg2-binary", specifier = "==2.9.*" },
     { name = "pydantic", specifier = "==2.10.*" },
     { name = "pydantic-settings", specifier = "==2.7.*" },
     { name = "python-multipart", specifier = "==0.0.*" },
+    { name = "rich", specifier = "==13.9.*" },
     { name = "safir", extras = ["db"], specifier = "==7.0.*" },
     { name = "sqlalchemy", extras = ["asyncio"], specifier = "==2.0.*" },
     { name = "structlog", specifier = "==24.4.*" },
@@ -1084,7 +996,7 @@ dev = [
 
 [[package]]
 name = "lsst-ctrl-bps"
-version = "28.2025.100"
+version = "28.2025.700"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "astropy" },
@@ -1097,14 +1009,14 @@ dependencies = [
     { name = "networkx" },
     { name = "pyyaml" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/29/41/36fa15fe9484ae8f4f85f13bd458f7be3761a63cf85965c0ed50a96d96a9/lsst_ctrl_bps-28.2025.100.tar.gz", hash = "sha256:66fec27a49b68f3e3434fa4b12fe41722e20018f8c1102bd316519bf359c0a1f", size = 110160 }
+sdist = { url = "https://files.pythonhosted.org/packages/21/90/1f33ea87a097a1a62b4fcebc123a234d461922d76c807677c155de14b8cd/lsst_ctrl_bps-28.2025.700.tar.gz", hash = "sha256:7c03d9f393f6d99e5473c3023b5a4bf5589cec6cc0bda0b4be9e066621472017", size = 111533 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/bc/94/ba46cc0f44c4a7457774b06cd6e2d745243eef7261243080cb3e7f6eebbe/lsst_ctrl_bps-28.2025.100-py3-none-any.whl", hash = "sha256:72298007103aed5867c53a07ddd791cd387c9d3a083f48b6039ca9f325b7245a", size = 99517 },
+    { url = "https://files.pythonhosted.org/packages/d1/26/98ea49e8865900c55c531661c87ed5625ec45e6bbdb2434ee03d317af59b/lsst_ctrl_bps-28.2025.700-py3-none-any.whl", hash = "sha256:043344d96848c999652a1d5fec3356aea338f0c7508fd3e3e4dff729b3847bf4", size = 99958 },
 ]
 
 [[package]]
 name = "lsst-ctrl-bps-htcondor"
-version = "28.2025.100"
+version = "28.2025.700"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "htcondor" },
@@ -1112,14 +1024,14 @@ dependencies = [
     { name = "lsst-daf-butler" },
     { name = "lsst-utils" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/c4/55/b63682e6ce1325ddc8674a242690b0a135a0fbd5468d98000fd620bd18b0/lsst_ctrl_bps_htcondor-28.2025.100.tar.gz", hash = "sha256:3ca6a1df35da3f3593dd84d7ad9316c71582668533db8b9dcaa2a8ac0139d57c", size = 72137 }
+sdist = { url = "https://files.pythonhosted.org/packages/bb/b5/1d5fcfbaa3ad2f851e0453d48e87881185b5467ccd5655634d6c7bdf0cd9/lsst_ctrl_bps_htcondor-28.2025.700.tar.gz", hash = "sha256:a453932d40480a145af50ea4bb26ebc858a94d7ae26b8ba56ed4f5747f9ae7f4", size = 73038 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/f6/21/d58de111cf1ccbc7a528076f751922626d0b5d3ea1d9c998e26d10eb8a1f/lsst_ctrl_bps_htcondor-28.2025.100-py3-none-any.whl", hash = "sha256:aecbd4e0ec28140fc378d013416015f885b0aea91b7d7027e779828506c8a19c", size = 60014 },
+    { url = "https://files.pythonhosted.org/packages/e6/f6/d37a924a7071a8e38fc6c3ffc7460ab7c5e4881585258a653105413f9344/lsst_ctrl_bps_htcondor-28.2025.700-py3-none-any.whl", hash = "sha256:0838231fcb51f41d6e26902c59fbaf01b25169ab526b31cbbf6bed5d358187ab", size = 60195 },
 ]
 
 [[package]]
 name = "lsst-ctrl-bps-panda"
-version = "28.2025.100"
+version = "28.2025.700"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "click" },
@@ -1134,14 +1046,14 @@ dependencies = [
     { name = "panda-client" },
     { name = "pyyaml" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/c6/52/b9c449d1d3f7632bf7c087c6d46e7be5cf465fe89369a4448d53656dc0d1/lsst_ctrl_bps_panda-28.2025.100.tar.gz", hash = "sha256:28b1139f0c3b2859e665d2d2da752fb643db94e69c81c8567f27d75428d076a1", size = 43547 }
+sdist = { url = "https://files.pythonhosted.org/packages/f8/d1/421ab1ad511b16ed96cdd8ad899dca5d9007acba3a9d6fbe775d8854ff04/lsst_ctrl_bps_panda-28.2025.700.tar.gz", hash = "sha256:2bb95a21ff7064b306aab72971cf26875778327e38ac77295b4c23867655e3b7", size = 43657 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/ed/87/13caf1d993dae75e8e1d70d75c4d39cb90fb69c492024b2b3fb49df88a57/lsst_ctrl_bps_panda-28.2025.100-py3-none-any.whl", hash = "sha256:0e7e134f79ee933ad0e02086dc5e92e62366fdc0aef7cdc6ad68966afba52c42", size = 53398 },
+    { url = "https://files.pythonhosted.org/packages/91/15/57fc10369f54203d9d2dab5adb80bc96b72c834a2e9d9a0c7d7773fa6759/lsst_ctrl_bps_panda-28.2025.700-py3-none-any.whl", hash = "sha256:7cd54e6015d4d1a3011fd0cee0362a16b342bd644d1ef2a8b6ac6ec5a49f0fe0", size = 53412 },
 ]
 
 [[package]]
 name = "lsst-ctrl-mpexec"
-version = "28.2025.100"
+version = "28.2025.700"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "astropy" },
@@ -1154,14 +1066,14 @@ dependencies = [
     { name = "psutil" },
     { name = "pydantic" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/0d/fb/a4b1aefdc30960924c762c3a7634d667e98f06e291a9f03d1fc7219e5ff5/lsst_ctrl_mpexec-28.2025.100.tar.gz", hash = "sha256:c87696e566213cec618e38844af0579518fce0398e5c1ef82648f6e6cf3cd96a", size = 129514 }
+sdist = { url = "https://files.pythonhosted.org/packages/af/c9/1878d4d3eafa6b536806996fa2438ecc12ecb3ac3f7c53bbd25a78d654c2/lsst_ctrl_mpexec-28.2025.700.tar.gz", hash = "sha256:750413472837629775af347937efa01911150b949be510efe681dabe43b11984", size = 130967 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/25/62/7523e37ab8c18a324a2c8a760d4a2d7add7b91ae60eb725cd1d9f09c1fc5/lsst_ctrl_mpexec-28.2025.100-py3-none-any.whl", hash = "sha256:d02b9a3be2a2da77d41f7c5d81bb456039aedcea1cd731fa738e4093ab5a2229", size = 126899 },
+    { url = "https://files.pythonhosted.org/packages/0c/f1/7ab22f6f1c32a78645a11cf42745dae070792b2d1e3eef143f73745946f9/lsst_ctrl_mpexec-28.2025.700-py3-none-any.whl", hash = "sha256:d07bbce0320f223b0f9d66ef770446ec1775e7594ce0cdad55164c20715d11ee", size = 127006 },
 ]
 
 [[package]]
 name = "lsst-daf-butler"
-version = "28.2025.100"
+version = "28.2025.700"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "astropy" },
@@ -1177,14 +1089,14 @@ dependencies = [
     { name = "pyyaml" },
     { name = "sqlalchemy" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/3a/3b/a43aaec2b3ed8ce592d8f6fea411967e521ec0ecaea9fd145f646bf69ccd/lsst_daf_butler-28.2025.100.tar.gz", hash = "sha256:5d51480204f4466c290be83d572594590e5e840cc9858b0fb42f1af2b7099cce", size = 1250020 }
+sdist = { url = "https://files.pythonhosted.org/packages/59/1f/72f4bfdadddad6890d78ed8b7cc4e3b1f75a0f5d484fee24ba754fd9b31d/lsst_daf_butler-28.2025.700.tar.gz", hash = "sha256:9d8eb8092f2ac66d8ace7962659eeed96ab5686026eb18dbdf38055c99b3fac4", size = 1257632 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/5c/a8/b339978d9863f463ac6733547b9187240ab72c3fb24080e89454d59dd097/lsst_daf_butler-28.2025.100-py3-none-any.whl", hash = "sha256:9f1a7b907aefd821f6b95ad29054067f62219d31b36b3b0e40c5568e0429d7b9", size = 1361416 },
+    { url = "https://files.pythonhosted.org/packages/59/d6/e27e59e6a095ecd2f573f555bc28dfe97953759a77d0e6fb4405476530de/lsst_daf_butler-28.2025.700-py3-none-any.whl", hash = "sha256:0bf3599b2e1bf487a297dc6cd73b645def9115600dd02b4c4eed71f16204ffae", size = 1368962 },
 ]
 
 [[package]]
 name = "lsst-daf-relation"
-version = "28.2025.100"
+version = "28.2025.700"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "deprecated" },
@@ -1192,27 +1104,27 @@ dependencies = [
     { name = "pydantic" },
     { name = "sqlalchemy" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/3d/ec/bfcf1b991de3ab8a7bc53353970460c3a352166f1bea90e254e6fea7cb89/lsst_daf_relation-28.2025.100.tar.gz", hash = "sha256:8f66b88eb63e6aa799d47518f12c5217ae46a0128930d993649d6f66aba5e96a", size = 89335 }
+sdist = { url = "https://files.pythonhosted.org/packages/b5/ab/804f25d7e10f9be33ab292887950fa769862a87bffa4c9a27dc975197ce2/lsst_daf_relation-28.2025.700.tar.gz", hash = "sha256:fe27fcda8d7e0527dcd4a48343bc8457745fd7ac74089959b979aef691e5f2f7", size = 89369 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/9d/01/5f4abe6fc1db6f645260ca2da3d621204e65dc94b8f108bffbafaea81d88/lsst_daf_relation-28.2025.100-py3-none-any.whl", hash = "sha256:25c8cc9f13ed1dd6df30dbf9b0bc132ed4abafa9a4358a46f5c35861bf6f477f", size = 104190 },
+    { url = "https://files.pythonhosted.org/packages/ad/a2/dfc4264c95a496782e061c2147f9c8972c870826c67d971493373beba6f4/lsst_daf_relation-28.2025.700-py3-none-any.whl", hash = "sha256:cc050dd12e13ec2145e8d04377732c2dbb87919c2affa641d1c58e6c6a4ffb28", size = 104192 },
 ]
 
 [[package]]
 name = "lsst-pex-config"
-version = "28.2025.100"
+version = "28.2025.700"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "numpy" },
     { name = "pyyaml" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/8a/31/2c46fe689a28a172b3943e02a0c9599fd25c85a21a125483b8e9518a8d2d/lsst_pex_config-28.2025.100.tar.gz", hash = "sha256:29e85b761b68ed77c487b85c4fe1f8180c0aed0a2a219c783da03c9eff7a5f55", size = 92904 }
+sdist = { url = "https://files.pythonhosted.org/packages/1c/7d/6c6e68b8fdfcfca6c4c4a8e8740c9013bbf00a278b7801a313fb2c5ed6c8/lsst_pex_config-28.2025.700.tar.gz", hash = "sha256:b2fa4614832a2d70ea73a072708d0db78570d1336c2199c4aaab6fa02ef9e44e", size = 93144 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/e3/90/40f77bb4684ccd5fdfc1a83d4eb59ed51d185359f3ac88750275f5d82cd3/lsst_pex_config-28.2025.100-py3-none-any.whl", hash = "sha256:74493a0886e995fad73b5f8631ff4a36ae324881a1ce3973facb1cec49ad69cd", size = 97006 },
+    { url = "https://files.pythonhosted.org/packages/43/11/3192775c3fb91caac830e7ad61463087cc1bcf1a05919634e1b2c70f54f8/lsst_pex_config-28.2025.700-py3-none-any.whl", hash = "sha256:69e27ead63e896f1f665467d3a9d1ef1a25feca24313326ef5a714c6fcc0cbd9", size = 97114 },
 ]
 
 [[package]]
 name = "lsst-pipe-base"
-version = "28.2025.100"
+version = "28.2025.700"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "astropy" },
@@ -1226,21 +1138,21 @@ dependencies = [
     { name = "pydantic" },
     { name = "pyyaml" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/0b/26/0bce9dc24e49d85ae03c615200827d06317aaaab78630ea93b6b90ef9b8a/lsst_pipe_base-28.2025.100.tar.gz", hash = "sha256:cd788794a6893b07ddf5c24170f5e8b39d8ecb5616e22195798dceec4349aa19", size = 373621 }
+sdist = { url = "https://files.pythonhosted.org/packages/f1/dd/bf47206fdc0cf3728675eb675aa02a80ad8a3eb349b155ed71e628894795/lsst_pipe_base-28.2025.700.tar.gz", hash = "sha256:920ddcc5411907d96788312bbdeb1597315e208d122a937c3133adddd27fe3d4", size = 394800 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/05/ce/6ac6081ae2d27b5c925c0a84752dc11cc78c9afeea65ed4f971252fcff26/lsst_pipe_base-28.2025.100-py3-none-any.whl", hash = "sha256:ff49af42c2b8339ad9442e9cae08d8de5cebc446bfb1d6b2fb383bffbd9d1aa2", size = 351841 },
+    { url = "https://files.pythonhosted.org/packages/6a/9f/0aa6cf50ca2fd4a921bb90f693cdf9f115c6ac168b4400c349207be45ef9/lsst_pipe_base-28.2025.700-py3-none-any.whl", hash = "sha256:54d4b3be129528b5b2a0c8ea04b5db1c2bbb16b0fc2768455a35a1e4fe7bfa54", size = 372337 },
 ]
 
 [[package]]
 name = "lsst-resources"
-version = "28.2025.100"
+version = "28.2025.700"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "lsst-utils" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/11/39/2275cca0c9a278210400d606b67af7d4654a0af45aa395fecf721f98dc65/lsst_resources-28.2025.100.tar.gz", hash = "sha256:b691a37c793e006d3a1eeaf12a88e9f75ade95a6e6f74935559f88e7bba14fa1", size = 108775 }
+sdist = { url = "https://files.pythonhosted.org/packages/b8/d5/91db4fd42beac7c58bb903bef89661d2caffa784ed870916384b1d9081c7/lsst_resources-28.2025.700.tar.gz", hash = "sha256:57e31a63bae979dd42857e9c338ea3eb8ca16def38ebccf2e0aa04371e786a3b", size = 109888 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/63/47/45dcbf6f410206bdd19b542a362a822558548606da6c6affbce3fbe96566/lsst_resources-28.2025.100-py3-none-any.whl", hash = "sha256:ca51a64d95bb8182c43cda45bca61c9476ee8edeae8f50a98565d929204d2e5f", size = 97929 },
+    { url = "https://files.pythonhosted.org/packages/2b/06/3229ff99a410002a559a94684dbe24de5e622640888b37472a77298c837d/lsst_resources-28.2025.700-py3-none-any.whl", hash = "sha256:002780a39345c55a4cd9444886eafb57d4c28b8433c6bdec85dac6628e8c1b4c", size = 97930 },
 ]
 
 [package.optional-dependencies]
@@ -1251,31 +1163,27 @@ s3 = [
 
 [[package]]
 name = "lsst-sphgeom"
-version = "28.2025.101"
+version = "28.2025.200"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "hpgeom" },
     { name = "numpy" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/40/d5/4d994eba03784e7179241b8bdc4d609ffc0d71d4fba1c2b85e686114f546/lsst_sphgeom-28.2025.101.tar.gz", hash = "sha256:c5b0649ffff6e1316c28c041db3ffea27b768b77ce35c9e7b264536eeafd0d0d", size = 160731 }
+sdist = { url = "https://files.pythonhosted.org/packages/82/95/6f17c19ef15b6f9328ca26a99eda0ff167fc764cb59f07dfedee1412d1f7/lsst_sphgeom-28.2025.200.tar.gz", hash = "sha256:7981f5654017d79e7de244fb57a034be8cd8d1a061c232adf7dda4351564b98e", size = 160746 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/8e/37/259247b6381783fde0d71ea27b564363503d81028cc33b75a1353bba9a06/lsst_sphgeom-28.2025.101-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9d9a40c31d45e7d8650e04d61b9171c933d8e2ed526c67125423463637665c9", size = 576501 },
-    { url = "https://files.pythonhosted.org/packages/e2/5d/c95ab6daf78b633acfe312416fd50f96ff992469e7089ea4181cb4570c83/lsst_sphgeom-28.2025.101-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e533b1a112beb087cf4ef7754567e46877a20d6dd16865578da44c1ad6157d4", size = 552649 },
-    { url = "https://files.pythonhosted.org/packages/51/ff/0afe5935c88d588ebab163c85e0e19d83f07a52babb4833bac0d1b9a8a2d/lsst_sphgeom-28.2025.101-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c875b7ff3e3177ddeb9104f8f3be530924448e4b9a7f7a0995a72e73a1f472c8", size = 703233 },
-    { url = "https://files.pythonhosted.org/packages/67/92/f6939d6f65f4cfd7ac80325bf6d796bd91bbf9ddbf8659287dc3a4260276/lsst_sphgeom-28.2025.101-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b429bb0f83355d1b61fa61b44f3b932b9e6337daf2155218673e03f92004e67", size = 758011 },
-    { url = "https://files.pythonhosted.org/packages/c2/ed/cc28f401867bf8b9f22cbca24c2f9489666b753b2fa58340f9be6abfbe29/lsst_sphgeom-28.2025.101-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:971a1cce177ebe5c1df9fc2b7136a285b93c427a8b34d3262a396530e43cbffb", size = 589015 },
-    { url = "https://files.pythonhosted.org/packages/08/e2/60adfd0b16f121deb178c235ed058d6dbb4830d9e9b34f675e1165f204ff/lsst_sphgeom-28.2025.101-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f4f250066e2c218ebb748ed72ea7a4ab1162f3dd3109ca203031b9178092b38e", size = 562345 },
-    { url = "https://files.pythonhosted.org/packages/5c/37/96f4ab0b818309d0f355d2c78f254d0bc4945c75cd3fdaf821c56932104f/lsst_sphgeom-28.2025.101-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b81a59a0b967a6531cdea352595c7a7f59f42886ea6b46db5cca2f35c15878e", size = 694066 },
-    { url = "https://files.pythonhosted.org/packages/b6/ca/3d03a62d567b37b94baf91de1c1936153a0f4a7f4748a1760d6e25974299/lsst_sphgeom-28.2025.101-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1df4c0a34420086e57249d0cf6d601f748e9e80bf766e91494c79591e8075e8d", size = 751079 },
-    { url = "https://files.pythonhosted.org/packages/8d/52/98c18865187a9967b7bd1d6143b31ae929ae55da92b2faed1688471d1563/lsst_sphgeom-28.2025.101-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5c0c6a83eb8d09c983710f4873ad55c68ffcf3567275922bda41acd4319755c5", size = 589264 },
-    { url = "https://files.pythonhosted.org/packages/6d/b6/4fe9835a0e7ea4ad7b6f8dcd7ad5b8e2a4abafe09166fe5118ca4efc3cc7/lsst_sphgeom-28.2025.101-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:07499da7442f321d190f5c34281c097310a7cfe14332e253ec6dde4f602fdc4f", size = 562189 },
-    { url = "https://files.pythonhosted.org/packages/a8/99/aac441a437b92c49bacf18c6895270acd43557e850e49023df0b4929d973/lsst_sphgeom-28.2025.101-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ef0c41d3ed7882217ad834499e9b009b1a1018eeb77a53dd901e9f02f1b0205", size = 697798 },
-    { url = "https://files.pythonhosted.org/packages/57/34/854ac18addd3281e8bbe178dc975adc0015623997b957aa910a38358f106/lsst_sphgeom-28.2025.101-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25aa1c6557a8a3a1851652d6d08633352fdb639bc58cf212187d95cea1133762", size = 751365 },
+    { url = "https://files.pythonhosted.org/packages/d6/fe/cc558ef18e1be65b6829f5ab0bc52661dfd5326d7c94017e6dad050589ec/lsst_sphgeom-28.2025.200-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4339d7660e78511751601ddbddec82ed54e7ca99dcca559b273240ee125b72cf", size = 576502 },
+    { url = "https://files.pythonhosted.org/packages/df/5e/8d5600bc64469cc40103f1a84a8c47ab8d021ed014e6a760ab1d683be12c/lsst_sphgeom-28.2025.200-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:315c5f527811c80c3b369535935a499287cf2323f12d66194f7c9f8406692ff6", size = 552651 },
+    { url = "https://files.pythonhosted.org/packages/8e/3a/b505d01b03d134bbcca5dc1a695a8e03dec0d5255197ff104545c8f74b8c/lsst_sphgeom-28.2025.200-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84566a2501c8d7a50c80f8aaace9ba652e9edd8f1853f09c9978c69e22882f2d", size = 703233 },
+    { url = "https://files.pythonhosted.org/packages/a6/81/e53d9767ac58e8b81d67c57afaf2f57cb2824a3e8d8d5fed4c00090eba5c/lsst_sphgeom-28.2025.200-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:159ce0893c26f4e428ede27f129f53a1a6a288dd28e51ce888df2c78fe491b1e", size = 758012 },
+    { url = "https://files.pythonhosted.org/packages/06/d4/11d43a41d397fa7da2cfa45cf6dc4708d8ea7babc3ef09c0527600d102e5/lsst_sphgeom-28.2025.200-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4e31e9a9ba8f561fe7eb1e8d9689e38439b96aba8e6e8c9685a1b0bfc36236e4", size = 589016 },
+    { url = "https://files.pythonhosted.org/packages/40/c9/3a9d894cf25cda8e8ba8cc240b47bb5a3bf9c2ddc973134a164bfcb99dc9/lsst_sphgeom-28.2025.200-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60899424fba076ab04689d02f1475b8256858431b0dec3f83439461b2a41ce37", size = 562347 },
+    { url = "https://files.pythonhosted.org/packages/a2/e7/9f35bcbe0cbd6f1c5aa993b915477170faaa9a14a3803a8e3d2d62cd9994/lsst_sphgeom-28.2025.200-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2eb25b6eee662ce7659420bfe9fef5934e2a30195d42cdd188293bd85dc94085", size = 694067 },
+    { url = "https://files.pythonhosted.org/packages/2a/45/b059c6f4a3a01f0d149a88a7b257fba592cca8c11666910da6a6f2b62b9e/lsst_sphgeom-28.2025.200-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e0a991a143e1ba29a91c7c4d7c40c6f75d10d60c50b0b04a29361bfa6e3f11c", size = 751081 },
 ]
 
 [[package]]
 name = "lsst-utils"
-version = "28.2025.100"
+version = "28.2025.700"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "astropy" },
@@ -1285,21 +1193,21 @@ dependencies = [
     { name = "pyyaml" },
     { name = "threadpoolctl" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/67/b9/78fe11d91c2cb03826e2d2d440e966a93bdaf0a1ca3a9983c80de67230a5/lsst_utils-28.2025.100.tar.gz", hash = "sha256:626affcd19ff0f4ec399a6f5a74badf58a59e600089c469922ee096a5c5e1cb1", size = 82188 }
+sdist = { url = "https://files.pythonhosted.org/packages/66/d8/a1b884e37e73e4f4e209f93e1918427645625ee99611d0c7284dbf02eb9e/lsst_utils-28.2025.700.tar.gz", hash = "sha256:306ec8ff74b3b1e8c6921b1ec8be56e21d9759d99d938ee55438fb424b12f239", size = 83398 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/ad/0f/fdaedbf5f472d0b3448c45da716a4126cef81e376b7c5d09e0f28880b33d/lsst_utils-28.2025.100-py3-none-any.whl", hash = "sha256:c23f121eea906a9b34c096541b0348dac4974a8d371b35e533ae437566ec7939", size = 66753 },
+    { url = "https://files.pythonhosted.org/packages/6b/c7/0efed04d865d1a4ad8113a0952a839e1ffca14b02dcc3d3574f81a466560/lsst_utils-28.2025.700-py3-none-any.whl", hash = "sha256:1f56e21b0532130fa45ad23c7ea87e93e5c2722942f4462f0701f774e6bf748d", size = 67633 },
 ]
 
 [[package]]
 name = "mako"
-version = "1.3.8"
+version = "1.3.9"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "markupsafe" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/5f/d9/8518279534ed7dace1795d5a47e49d5299dd0994eed1053996402a8902f9/mako-1.3.8.tar.gz", hash = "sha256:577b97e414580d3e088d47c2dbbe9594aa7a5146ed2875d4dfa9075af2dd3cc8", size = 392069 }
+sdist = { url = "https://files.pythonhosted.org/packages/62/4f/ddb1965901bc388958db9f0c991255b2c469349a741ae8c9cd8a562d70a6/mako-1.3.9.tar.gz", hash = "sha256:b5d65ff3462870feec922dbccf38f6efb44e5714d7b593a656be86663d8600ac", size = 392195 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/1e/bf/7a6a36ce2e4cafdfb202752be68850e22607fccd692847c45c1ae3c17ba6/Mako-1.3.8-py3-none-any.whl", hash = "sha256:42f48953c7eb91332040ff567eb7eea69b22e7a4affbc5ba8e845e8f730f6627", size = 78569 },
+    { url = "https://files.pythonhosted.org/packages/cd/83/de0a49e7de540513f53ab5d2e105321dedeb08a8f5850f0208decf4390ec/Mako-1.3.9-py3-none-any.whl", hash = "sha256:95920acccb578427a9aa38e37a186b1e43156c87260d7ba18ca63aa4c7cbd3a1", size = 78456 },
 ]
 
 [[package]]
@@ -1340,26 +1248,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 },
     { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 },
     { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 },
-    { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 },
-    { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 },
-    { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 },
-    { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 },
-    { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 },
-    { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 },
-    { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 },
-    { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 },
-    { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 },
-    { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 },
-    { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 },
-    { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 },
-    { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 },
-    { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 },
-    { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 },
-    { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 },
-    { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 },
-    { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 },
-    { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 },
-    { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 },
 ]
 
 [[package]]
@@ -1373,33 +1261,27 @@ wheels = [
 
 [[package]]
 name = "mypy"
-version = "1.14.1"
+version = "1.15.0"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "mypy-extensions" },
     { name = "typing-extensions" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/b9/eb/2c92d8ea1e684440f54fa49ac5d9a5f19967b7b472a281f419e69a8d228e/mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6", size = 3216051 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/da/11/a9422850fd506edbcdc7f6090682ecceaf1f87b9dd847f9df79942da8506/mypy-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f995e511de847791c3b11ed90084a7a0aafdc074ab88c5a9711622fe4751138c", size = 11120432 },
-    { url = "https://files.pythonhosted.org/packages/b6/9e/47e450fd39078d9c02d620545b2cb37993a8a8bdf7db3652ace2f80521ca/mypy-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d64169ec3b8461311f8ce2fd2eb5d33e2d0f2c7b49116259c51d0d96edee48d1", size = 10279515 },
-    { url = "https://files.pythonhosted.org/packages/01/b5/6c8d33bd0f851a7692a8bfe4ee75eb82b6983a3cf39e5e32a5d2a723f0c1/mypy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba24549de7b89b6381b91fbc068d798192b1b5201987070319889e93038967a8", size = 12025791 },
-    { url = "https://files.pythonhosted.org/packages/f0/4c/e10e2c46ea37cab5c471d0ddaaa9a434dc1d28650078ac1b56c2d7b9b2e4/mypy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:183cf0a45457d28ff9d758730cd0210419ac27d4d3f285beda038c9083363b1f", size = 12749203 },
-    { url = "https://files.pythonhosted.org/packages/88/55/beacb0c69beab2153a0f57671ec07861d27d735a0faff135a494cd4f5020/mypy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f2a0ecc86378f45347f586e4163d1769dd81c5a223d577fe351f26b179e148b1", size = 12885900 },
-    { url = "https://files.pythonhosted.org/packages/a2/75/8c93ff7f315c4d086a2dfcde02f713004357d70a163eddb6c56a6a5eff40/mypy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:ad3301ebebec9e8ee7135d8e3109ca76c23752bac1e717bc84cd3836b4bf3eae", size = 9777869 },
-    { url = "https://files.pythonhosted.org/packages/43/1b/b38c079609bb4627905b74fc6a49849835acf68547ac33d8ceb707de5f52/mypy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30ff5ef8519bbc2e18b3b54521ec319513a26f1bba19a7582e7b1f58a6e69f14", size = 11266668 },
-    { url = "https://files.pythonhosted.org/packages/6b/75/2ed0d2964c1ffc9971c729f7a544e9cd34b2cdabbe2d11afd148d7838aa2/mypy-1.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb9f255c18052343c70234907e2e532bc7e55a62565d64536dbc7706a20b78b9", size = 10254060 },
-    { url = "https://files.pythonhosted.org/packages/a1/5f/7b8051552d4da3c51bbe8fcafffd76a6823779101a2b198d80886cd8f08e/mypy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b4e3413e0bddea671012b063e27591b953d653209e7a4fa5e48759cda77ca11", size = 11933167 },
-    { url = "https://files.pythonhosted.org/packages/04/90/f53971d3ac39d8b68bbaab9a4c6c58c8caa4d5fd3d587d16f5927eeeabe1/mypy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:553c293b1fbdebb6c3c4030589dab9fafb6dfa768995a453d8a5d3b23784af2e", size = 12864341 },
-    { url = "https://files.pythonhosted.org/packages/03/d2/8bc0aeaaf2e88c977db41583559319f1821c069e943ada2701e86d0430b7/mypy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fad79bfe3b65fe6a1efaed97b445c3d37f7be9fdc348bdb2d7cac75579607c89", size = 12972991 },
-    { url = "https://files.pythonhosted.org/packages/6f/17/07815114b903b49b0f2cf7499f1c130e5aa459411596668267535fe9243c/mypy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fa2220e54d2946e94ab6dbb3ba0a992795bd68b16dc852db33028df2b00191b", size = 9879016 },
-    { url = "https://files.pythonhosted.org/packages/9e/15/bb6a686901f59222275ab228453de741185f9d54fecbaacec041679496c6/mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255", size = 11252097 },
-    { url = "https://files.pythonhosted.org/packages/f8/b3/8b0f74dfd072c802b7fa368829defdf3ee1566ba74c32a2cb2403f68024c/mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34", size = 10239728 },
-    { url = "https://files.pythonhosted.org/packages/c5/9b/4fd95ab20c52bb5b8c03cc49169be5905d931de17edfe4d9d2986800b52e/mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a", size = 11924965 },
-    { url = "https://files.pythonhosted.org/packages/56/9d/4a236b9c57f5d8f08ed346914b3f091a62dd7e19336b2b2a0d85485f82ff/mypy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4b19b03fdf54f3c5b2fa474c56b4c13c9dbfb9a2db4370ede7ec11a2c5927d9", size = 12867660 },
-    { url = "https://files.pythonhosted.org/packages/40/88/a61a5497e2f68d9027de2bb139c7bb9abaeb1be1584649fa9d807f80a338/mypy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c911fde686394753fff899c409fd4e16e9b294c24bfd5e1ea4675deae1ac6fd", size = 12969198 },
-    { url = "https://files.pythonhosted.org/packages/54/da/3d6fc5d92d324701b0c23fb413c853892bfe0e1dbe06c9138037d459756b/mypy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8b21525cb51671219f5307be85f7e646a153e5acc656e5cebf64bfa076c50107", size = 9885276 },
-    { url = "https://files.pythonhosted.org/packages/a0/b5/32dd67b69a16d088e533962e5044e51004176a9952419de0370cdaead0f8/mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1", size = 2752905 },
+sdist = { url = "https://files.pythonhosted.org/packages/ce/43/d5e49a86afa64bd3839ea0d5b9c7103487007d728e1293f52525d6d5486a/mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43", size = 3239717 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/03/bc/f6339726c627bd7ca1ce0fa56c9ae2d0144604a319e0e339bdadafbbb599/mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f", size = 10662338 },
+    { url = "https://files.pythonhosted.org/packages/e2/90/8dcf506ca1a09b0d17555cc00cd69aee402c203911410136cd716559efe7/mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5", size = 9787540 },
+    { url = "https://files.pythonhosted.org/packages/05/05/a10f9479681e5da09ef2f9426f650d7b550d4bafbef683b69aad1ba87457/mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e", size = 11538051 },
+    { url = "https://files.pythonhosted.org/packages/e9/9a/1f7d18b30edd57441a6411fcbc0c6869448d1a4bacbaee60656ac0fc29c8/mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c", size = 12286751 },
+    { url = "https://files.pythonhosted.org/packages/72/af/19ff499b6f1dafcaf56f9881f7a965ac2f474f69f6f618b5175b044299f5/mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f", size = 12421783 },
+    { url = "https://files.pythonhosted.org/packages/96/39/11b57431a1f686c1aed54bf794870efe0f6aeca11aca281a0bd87a5ad42c/mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f", size = 9265618 },
+    { url = "https://files.pythonhosted.org/packages/98/3a/03c74331c5eb8bd025734e04c9840532226775c47a2c39b56a0c8d4f128d/mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd", size = 10793981 },
+    { url = "https://files.pythonhosted.org/packages/f0/1a/41759b18f2cfd568848a37c89030aeb03534411eef981df621d8fad08a1d/mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f", size = 9749175 },
+    { url = "https://files.pythonhosted.org/packages/12/7e/873481abf1ef112c582db832740f4c11b2bfa510e829d6da29b0ab8c3f9c/mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464", size = 11455675 },
+    { url = "https://files.pythonhosted.org/packages/b3/d0/92ae4cde706923a2d3f2d6c39629134063ff64b9dedca9c1388363da072d/mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee", size = 12410020 },
+    { url = "https://files.pythonhosted.org/packages/46/8b/df49974b337cce35f828ba6fda228152d6db45fed4c86ba56ffe442434fd/mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e", size = 12498582 },
+    { url = "https://files.pythonhosted.org/packages/13/50/da5203fcf6c53044a0b699939f31075c45ae8a4cadf538a9069b165c1050/mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22", size = 9366614 },
+    { url = "https://files.pythonhosted.org/packages/09/4e/a7d65c7322c510de2c409ff3828b03354a7c43f5a8ed458a7a131b41c7b9/mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e", size = 2221777 },
 ]
 
 [[package]]
@@ -1455,26 +1337,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/ad/7a/442965e98b34e0ae9da319f075b387bcb9a1e0658276cc63adb8c9686f7b/numpy-2.1.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02135ade8b8a84011cbb67dc44e07c58f28575cf9ecf8ab304e51c05528c19f0", size = 14082705 },
     { url = "https://files.pythonhosted.org/packages/ac/b6/26108cf2cfa5c7e03fb969b595c93131eab4a399762b51ce9ebec2332e80/numpy-2.1.3-cp312-cp312-win32.whl", hash = "sha256:e6988e90fcf617da2b5c78902fe8e668361b43b4fe26dbf2d7b0f8034d4cafb9", size = 6239077 },
     { url = "https://files.pythonhosted.org/packages/a6/84/fa11dad3404b7634aaab50733581ce11e5350383311ea7a7010f464c0170/numpy-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:0d30c543f02e84e92c4b1f415b7c6b5326cbe45ee7882b6b77db7195fb971e3a", size = 12566858 },
-    { url = "https://files.pythonhosted.org/packages/4d/0b/620591441457e25f3404c8057eb924d04f161244cb8a3680d529419aa86e/numpy-2.1.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96fe52fcdb9345b7cd82ecd34547fca4321f7656d500eca497eb7ea5a926692f", size = 20836263 },
-    { url = "https://files.pythonhosted.org/packages/45/e1/210b2d8b31ce9119145433e6ea78046e30771de3fe353f313b2778142f34/numpy-2.1.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f653490b33e9c3a4c1c01d41bc2aef08f9475af51146e4a7710c450cf9761598", size = 13507771 },
-    { url = "https://files.pythonhosted.org/packages/55/44/aa9ee3caee02fa5a45f2c3b95cafe59c44e4b278fbbf895a93e88b308555/numpy-2.1.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dc258a761a16daa791081d026f0ed4399b582712e6fc887a95af09df10c5ca57", size = 5075805 },
-    { url = "https://files.pythonhosted.org/packages/78/d6/61de6e7e31915ba4d87bbe1ae859e83e6582ea14c6add07c8f7eefd8488f/numpy-2.1.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:016d0f6f5e77b0f0d45d77387ffa4bb89816b57c835580c3ce8e099ef830befe", size = 6608380 },
-    { url = "https://files.pythonhosted.org/packages/3e/46/48bdf9b7241e317e6cf94276fe11ba673c06d1fdf115d8b4ebf616affd1a/numpy-2.1.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c181ba05ce8299c7aa3125c27b9c2167bca4a4445b7ce73d5febc411ca692e43", size = 13602451 },
-    { url = "https://files.pythonhosted.org/packages/70/50/73f9a5aa0810cdccda9c1d20be3cbe4a4d6ea6bfd6931464a44c95eef731/numpy-2.1.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5641516794ca9e5f8a4d17bb45446998c6554704d888f86df9b200e66bdcce56", size = 16039822 },
-    { url = "https://files.pythonhosted.org/packages/ad/cd/098bc1d5a5bc5307cfc65ee9369d0ca658ed88fbd7307b0d49fab6ca5fa5/numpy-2.1.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ea4dedd6e394a9c180b33c2c872b92f7ce0f8e7ad93e9585312b0c5a04777a4a", size = 16411822 },
-    { url = "https://files.pythonhosted.org/packages/83/a2/7d4467a2a6d984549053b37945620209e702cf96a8bc658bc04bba13c9e2/numpy-2.1.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0df3635b9c8ef48bd3be5f862cf71b0a4716fa0e702155c45067c6b711ddcef", size = 14079598 },
-    { url = "https://files.pythonhosted.org/packages/e9/6a/d64514dcecb2ee70bfdfad10c42b76cab657e7ee31944ff7a600f141d9e9/numpy-2.1.3-cp313-cp313-win32.whl", hash = "sha256:50ca6aba6e163363f132b5c101ba078b8cbd3fa92c7865fd7d4d62d9779ac29f", size = 6236021 },
-    { url = "https://files.pythonhosted.org/packages/bb/f9/12297ed8d8301a401e7d8eb6b418d32547f1d700ed3c038d325a605421a4/numpy-2.1.3-cp313-cp313-win_amd64.whl", hash = "sha256:747641635d3d44bcb380d950679462fae44f54b131be347d5ec2bce47d3df9ed", size = 12560405 },
-    { url = "https://files.pythonhosted.org/packages/a7/45/7f9244cd792e163b334e3a7f02dff1239d2890b6f37ebf9e82cbe17debc0/numpy-2.1.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:996bb9399059c5b82f76b53ff8bb686069c05acc94656bb259b1d63d04a9506f", size = 20859062 },
-    { url = "https://files.pythonhosted.org/packages/b1/b4/a084218e7e92b506d634105b13e27a3a6645312b93e1c699cc9025adb0e1/numpy-2.1.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:45966d859916ad02b779706bb43b954281db43e185015df6eb3323120188f9e4", size = 13515839 },
-    { url = "https://files.pythonhosted.org/packages/27/45/58ed3f88028dcf80e6ea580311dc3edefdd94248f5770deb980500ef85dd/numpy-2.1.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:baed7e8d7481bfe0874b566850cb0b85243e982388b7b23348c6db2ee2b2ae8e", size = 5116031 },
-    { url = "https://files.pythonhosted.org/packages/37/a8/eb689432eb977d83229094b58b0f53249d2209742f7de529c49d61a124a0/numpy-2.1.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f7f672a3388133335589cfca93ed468509cb7b93ba3105fce780d04a6576a0", size = 6629977 },
-    { url = "https://files.pythonhosted.org/packages/42/a3/5355ad51ac73c23334c7caaed01adadfda49544f646fcbfbb4331deb267b/numpy-2.1.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7aac50327da5d208db2eec22eb11e491e3fe13d22653dce51b0f4109101b408", size = 13575951 },
-    { url = "https://files.pythonhosted.org/packages/c4/70/ea9646d203104e647988cb7d7279f135257a6b7e3354ea6c56f8bafdb095/numpy-2.1.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4394bc0dbd074b7f9b52024832d16e019decebf86caf909d94f6b3f77a8ee3b6", size = 16022655 },
-    { url = "https://files.pythonhosted.org/packages/14/ce/7fc0612903e91ff9d0b3f2eda4e18ef9904814afcae5b0f08edb7f637883/numpy-2.1.3-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:50d18c4358a0a8a53f12a8ba9d772ab2d460321e6a93d6064fc22443d189853f", size = 16399902 },
-    { url = "https://files.pythonhosted.org/packages/ef/62/1d3204313357591c913c32132a28f09a26357e33ea3c4e2fe81269e0dca1/numpy-2.1.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:14e253bd43fc6b37af4921b10f6add6925878a42a0c5fe83daee390bca80bc17", size = 14067180 },
-    { url = "https://files.pythonhosted.org/packages/24/d7/78a40ed1d80e23a774cb8a34ae8a9493ba1b4271dde96e56ccdbab1620ef/numpy-2.1.3-cp313-cp313t-win32.whl", hash = "sha256:08788d27a5fd867a663f6fc753fd7c3ad7e92747efc73c53bca2f19f8bc06f48", size = 6291907 },
-    { url = "https://files.pythonhosted.org/packages/86/09/a5ab407bd7f5f5599e6a9261f964ace03a73e7c6928de906981c31c38082/numpy-2.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2564fbdf2b99b3f815f2107c1bbc93e2de8ee655a69c261363a1172a79a257d4", size = 12644098 },
 ]
 
 [[package]]
@@ -1500,28 +1362,25 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/ac/b8/268ba130550594d2cb34691db4d2c843991c8410351cdaf191666c63587d/panda_client_light-1.5.82-py2.py3-none-any.whl", hash = "sha256:2f07debd4958c35f42b104f2ef937f7d598ea52142d4e6126e57f6c8e88bbaa3", size = 163531 },
 ]
 
-[[package]]
-name = "pause"
-version = "0.3"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/9f/7f/e48f80883c7a74a3303d0a62f1d48b3f6a097420ad9eda23e8fc6e07be2b/pause-0.3.tar.gz", hash = "sha256:82284ec6213376f718a86a51cf1df04eaa77ce85e349bff63c0071e7db33daba", size = 4384 }
-
 [[package]]
 name = "pbr"
-version = "6.1.0"
+version = "6.1.1"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/b2/35/80cf8f6a4f34017a7fe28242dc45161a1baa55c41563c354d8147e8358b2/pbr-6.1.0.tar.gz", hash = "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24", size = 124032 }
+dependencies = [
+    { name = "setuptools" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/01/d2/510cc0d218e753ba62a1bc1434651db3cd797a9716a0a66cc714cb4f0935/pbr-6.1.1.tar.gz", hash = "sha256:93ea72ce6989eb2eed99d0f75721474f69ad88128afdef5ac377eb797c4bf76b", size = 125702 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/1d/44/6a65ecd630393d47ad3e7d5354768cb7f9a10b3a0eb2cd8c6f52b28211ee/pbr-6.1.0-py2.py3-none-any.whl", hash = "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a", size = 108529 },
+    { url = "https://files.pythonhosted.org/packages/47/ac/684d71315abc7b1214d59304e23a982472967f6bf4bde5a98f1503f648dc/pbr-6.1.1-py2.py3-none-any.whl", hash = "sha256:38d4daea5d9fa63b3f626131b9d34947fd0c8be9b05a29276870580050a25a76", size = 108997 },
 ]
 
 [[package]]
 name = "pip"
-version = "24.3.1"
+version = "25.0.1"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/f4/b1/b422acd212ad7eedddaf7981eee6e5de085154ff726459cf2da7c5a184c1/pip-24.3.1.tar.gz", hash = "sha256:ebcb60557f2aefabc2e0f918751cd24ea0d56d8ec5445fe1807f1d2109660b99", size = 1931073 }
+sdist = { url = "https://files.pythonhosted.org/packages/70/53/b309b4a497b09655cb7e07088966881a57d082f48ac3cb54ea729fd2c6cf/pip-25.0.1.tar.gz", hash = "sha256:88f96547ea48b940a3a385494e181e29fb8637898f88d88737c5049780f196ea", size = 1950850 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/ef/7d/500c9ad20238fcfcb4cb9243eede163594d7020ce87bd9610c9e02771876/pip-24.3.1-py3-none-any.whl", hash = "sha256:3790624780082365f47549d032f3770eeb2b1e8bd1f7b2e02dace1afa361b4ed", size = 1822182 },
+    { url = "https://files.pythonhosted.org/packages/c9/bc/b7db44f5f39f9d0494071bddae6880eb645970366d0a200022a1a93d57f5/pip-25.0.1-py3-none-any.whl", hash = "sha256:c46efd13b6aa8279f33f2864459c8ce587ea6a1a59ee20de055868d8f7688f7f", size = 1841526 },
 ]
 
 [[package]]
@@ -1535,20 +1394,20 @@ wheels = [
 
 [[package]]
 name = "playwright"
-version = "1.49.1"
+version = "1.50.0"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "greenlet" },
     { name = "pyee" },
 ]
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/ab/be/01025581052e43eb698092c4328d7497ca62bcb5c83f15a611d4a71b4b92/playwright-1.49.1-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:1041ffb45a0d0bc44d698d3a5aa3ac4b67c9bd03540da43a0b70616ad52592b8", size = 39559859 },
-    { url = "https://files.pythonhosted.org/packages/79/25/ef1010a42cc7d576282015d983c5451d73e369b198b6eb32a177fae281f8/playwright-1.49.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9f38ed3d0c1f4e0a6d1c92e73dd9a61f8855133249d6f0cec28648d38a7137be", size = 38808973 },
-    { url = "https://files.pythonhosted.org/packages/70/4b/3930cf10f303a10d493a382e4448aaff898b4065698b3b8d92f902e53e08/playwright-1.49.1-py3-none-macosx_11_0_universal2.whl", hash = "sha256:3be48c6d26dc819ca0a26567c1ae36a980a0303dcd4249feb6f59e115aaddfb8", size = 39559863 },
-    { url = "https://files.pythonhosted.org/packages/9a/c1/ea765e72a746dc7ec2ce155ffea29d454e7171db78f3c09185e888387246/playwright-1.49.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:753ca90ee31b4b03d165cfd36e477309ebf2b4381953f2a982ff612d85b147d2", size = 44163300 },
-    { url = "https://files.pythonhosted.org/packages/5a/52/95efac704bf36b770a2522d88a6dee298042845d10bfb35f7ca0fcc36d91/playwright-1.49.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd9bc8dab37aa25198a01f555f0a2e2c3813fe200fef018ac34dfe86b34994b9", size = 43744353 },
-    { url = "https://files.pythonhosted.org/packages/f9/97/a3fccc9aaa6da83890772e9980703b0ea6b1e1ad42042fb50df3aef6c641/playwright-1.49.1-py3-none-win32.whl", hash = "sha256:43b304be67f096058e587dac453ece550eff87b8fbed28de30f4f022cc1745bb", size = 34060663 },
-    { url = "https://files.pythonhosted.org/packages/71/a9/bd88ac0bd498c91aab3aba2e393d1fa59f72a7243e9265ccbf4861ca4f64/playwright-1.49.1-py3-none-win_amd64.whl", hash = "sha256:47b23cb346283278f5b4d1e1990bcb6d6302f80c0aa0ca93dd0601a1400191df", size = 34060667 },
+    { url = "https://files.pythonhosted.org/packages/0d/5e/068dea3c96e9c09929b45c92cf7e573403b52a89aa463f89b9da9b87b7a4/playwright-1.50.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:f36d754a6c5bd9bf7f14e8f57a2aea6fd08f39ca4c8476481b9c83e299531148", size = 40277564 },
+    { url = "https://files.pythonhosted.org/packages/78/85/b3deb3d2add00d2a6ee74bf6f57ccefb30efc400fd1b7b330ba9a3626330/playwright-1.50.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:40f274384591dfd27f2b014596250b2250c843ed1f7f4ef5d2960ecb91b4961e", size = 39521844 },
+    { url = "https://files.pythonhosted.org/packages/f3/f6/002b3d98df9c84296fea84f070dc0d87c2270b37f423cf076a913370d162/playwright-1.50.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:9922ef9bcd316995f01e220acffd2d37a463b4ad10fd73e388add03841dfa230", size = 40277563 },
+    { url = "https://files.pythonhosted.org/packages/b9/63/c9a73736e434df894e484278dddc0bf154312ff8d0f16d516edb790a7d42/playwright-1.50.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:8fc628c492d12b13d1f347137b2ac6c04f98197ff0985ef0403a9a9ee0d39131", size = 45076712 },
+    { url = "https://files.pythonhosted.org/packages/bd/2c/a54b5a64cc7d1a62f2d944c5977fb3c88e74d76f5cdc7966e717426bce66/playwright-1.50.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcff35f72db2689a79007aee78f1b0621a22e6e3d6c1f58aaa9ac805bf4497c", size = 44493111 },
+    { url = "https://files.pythonhosted.org/packages/2b/4a/047cbb2ffe1249bd7a56441fc3366fb4a8a1f44bc36a9061d10edfda2c86/playwright-1.50.0-py3-none-win32.whl", hash = "sha256:3b906f4d351260016a8c5cc1e003bb341651ae682f62213b50168ed581c7558a", size = 34784543 },
+    { url = "https://files.pythonhosted.org/packages/bc/2b/e944e10c9b18e77e43d3bb4d6faa323f6cc27597db37b75bc3fd796adfd5/playwright-1.50.0-py3-none-win_amd64.whl", hash = "sha256:1859423da82de631704d5e3d88602d755462b0906824c1debe140979397d2e8d", size = 34784546 },
 ]
 
 [[package]]
@@ -1562,7 +1421,7 @@ wheels = [
 
 [[package]]
 name = "pre-commit"
-version = "4.0.1"
+version = "4.1.0"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "cfgv" },
@@ -1571,24 +1430,24 @@ dependencies = [
     { name = "pyyaml" },
     { name = "virtualenv" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/2e/c8/e22c292035f1bac8b9f5237a2622305bc0304e776080b246f3df57c4ff9f/pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2", size = 191678 }
+sdist = { url = "https://files.pythonhosted.org/packages/2a/13/b62d075317d8686071eb843f0bb1f195eb332f48869d3c31a4c6f1e063ac/pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4", size = 193330 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/16/8f/496e10d51edd6671ebe0432e33ff800aa86775d2d147ce7d43389324a525/pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878", size = 218713 },
+    { url = "https://files.pythonhosted.org/packages/43/b3/df14c580d82b9627d173ceea305ba898dca135feb360b6d84019d0803d3b/pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b", size = 220560 },
 ]
 
 [[package]]
 name = "psutil"
-version = "6.1.1"
+version = "7.0.0"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/1f/5a/07871137bb752428aa4b659f910b399ba6f291156bdea939be3e96cae7cb/psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5", size = 508502 }
+sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/61/99/ca79d302be46f7bdd8321089762dd4476ee725fce16fc2b2e1dbba8cac17/psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8", size = 247511 },
-    { url = "https://files.pythonhosted.org/packages/0b/6b/73dbde0dd38f3782905d4587049b9be64d76671042fdcaf60e2430c6796d/psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377", size = 248985 },
-    { url = "https://files.pythonhosted.org/packages/17/38/c319d31a1d3f88c5b79c68b3116c129e5133f1822157dd6da34043e32ed6/psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003", size = 284488 },
-    { url = "https://files.pythonhosted.org/packages/9c/39/0f88a830a1c8a3aba27fededc642da37613c57cbff143412e3536f89784f/psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160", size = 287477 },
-    { url = "https://files.pythonhosted.org/packages/47/da/99f4345d4ddf2845cb5b5bd0d93d554e84542d116934fde07a0c50bd4e9f/psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3", size = 289017 },
-    { url = "https://files.pythonhosted.org/packages/38/53/bd755c2896f4461fd4f36fa6a6dcb66a88a9e4b9fd4e5b66a77cf9d4a584/psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53", size = 250602 },
-    { url = "https://files.pythonhosted.org/packages/7b/d7/7831438e6c3ebbfa6e01a927127a6cb42ad3ab844247f3c5b96bea25d73d/psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649", size = 254444 },
+    { url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051 },
+    { url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535 },
+    { url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004 },
+    { url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986 },
+    { url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544 },
+    { url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053 },
+    { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885 },
 ]
 
 [[package]]
@@ -1621,52 +1480,28 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/2d/70/aa69c9f69cf09a01da224909ff6ce8b68faeef476f00f7ec377e8f03be70/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3cc28a6fd5a4a26224007712e79b81dbaee2ffb90ff406256158ec4d7b52b47", size = 2959312 },
     { url = "https://files.pythonhosted.org/packages/d3/bd/213e59854fafe87ba47814bf413ace0dcee33a89c8c8c814faca6bc7cf3c/psycopg2_binary-2.9.10-cp312-cp312-win32.whl", hash = "sha256:ec8a77f521a17506a24a5f626cb2aee7850f9b69a0afe704586f63a464f3cd64", size = 1025191 },
     { url = "https://files.pythonhosted.org/packages/92/29/06261ea000e2dc1e22907dbbc483a1093665509ea586b29b8986a0e56733/psycopg2_binary-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:18c5ee682b9c6dd3696dad6e54cc7ff3a1a9020df6a5c0f861ef8bfd338c3ca0", size = 1164031 },
-    { url = "https://files.pythonhosted.org/packages/3e/30/d41d3ba765609c0763505d565c4d12d8f3c79793f0d0f044ff5a28bf395b/psycopg2_binary-2.9.10-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:26540d4a9a4e2b096f1ff9cce51253d0504dca5a85872c7f7be23be5a53eb18d", size = 3044699 },
-    { url = "https://files.pythonhosted.org/packages/35/44/257ddadec7ef04536ba71af6bc6a75ec05c5343004a7ec93006bee66c0bc/psycopg2_binary-2.9.10-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e217ce4d37667df0bc1c397fdcd8de5e81018ef305aed9415c3b093faaeb10fb", size = 3275245 },
-    { url = "https://files.pythonhosted.org/packages/1b/11/48ea1cd11de67f9efd7262085588790a95d9dfcd9b8a687d46caf7305c1a/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:245159e7ab20a71d989da00f280ca57da7641fa2cdcf71749c193cea540a74f7", size = 2851631 },
-    { url = "https://files.pythonhosted.org/packages/62/e0/62ce5ee650e6c86719d621a761fe4bc846ab9eff8c1f12b1ed5741bf1c9b/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c4ded1a24b20021ebe677b7b08ad10bf09aac197d6943bfe6fec70ac4e4690d", size = 3082140 },
-    { url = "https://files.pythonhosted.org/packages/27/ce/63f946c098611f7be234c0dd7cb1ad68b0b5744d34f68062bb3c5aa510c8/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3abb691ff9e57d4a93355f60d4f4c1dd2d68326c968e7db17ea96df3c023ef73", size = 3264762 },
-    { url = "https://files.pythonhosted.org/packages/43/25/c603cd81402e69edf7daa59b1602bd41eb9859e2824b8c0855d748366ac9/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8608c078134f0b3cbd9f89b34bd60a943b23fd33cc5f065e8d5f840061bd0673", size = 3020967 },
-    { url = "https://files.pythonhosted.org/packages/5f/d6/8708d8c6fca531057fa170cdde8df870e8b6a9b136e82b361c65e42b841e/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:230eeae2d71594103cd5b93fd29d1ace6420d0b86f4778739cb1a5a32f607d1f", size = 2872326 },
-    { url = "https://files.pythonhosted.org/packages/ce/ac/5b1ea50fc08a9df82de7e1771537557f07c2632231bbab652c7e22597908/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909", size = 2822712 },
-    { url = "https://files.pythonhosted.org/packages/c4/fc/504d4503b2abc4570fac3ca56eb8fed5e437bf9c9ef13f36b6621db8ef00/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1", size = 2920155 },
-    { url = "https://files.pythonhosted.org/packages/b2/d1/323581e9273ad2c0dbd1902f3fb50c441da86e894b6e25a73c3fda32c57e/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567", size = 2959356 },
-    { url = "https://files.pythonhosted.org/packages/08/50/d13ea0a054189ae1bc21af1d85b6f8bb9bbc5572991055d70ad9006fe2d6/psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142", size = 2569224 },
 ]
 
 [[package]]
 name = "pyarrow"
-version = "18.1.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/7f/7b/640785a9062bb00314caa8a387abce547d2a420cf09bd6c715fe659ccffb/pyarrow-18.1.0.tar.gz", hash = "sha256:9386d3ca9c145b5539a1cfc75df07757dff870168c959b473a0bccbc3abc8c73", size = 1118671 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/9e/4d/a4988e7d82f4fbc797715db4185939a658eeffb07a25bab7262bed1ea076/pyarrow-18.1.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:eaeabf638408de2772ce3d7793b2668d4bb93807deed1725413b70e3156a7854", size = 29554860 },
-    { url = "https://files.pythonhosted.org/packages/59/03/3a42c5c1e4bd4c900ab62aa1ff6b472bdb159ba8f1c3e5deadab7222244f/pyarrow-18.1.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:3b2e2239339c538f3464308fd345113f886ad031ef8266c6f004d49769bb074c", size = 30867076 },
-    { url = "https://files.pythonhosted.org/packages/75/7e/332055ac913373e89256dce9d14b7708f55f7bd5be631456c897f0237738/pyarrow-18.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f39a2e0ed32a0970e4e46c262753417a60c43a3246972cfc2d3eb85aedd01b21", size = 39212135 },
-    { url = "https://files.pythonhosted.org/packages/8c/64/5099cdb325828722ef7ffeba9a4696f238eb0cdeae227f831c2d77fcf1bd/pyarrow-18.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e31e9417ba9c42627574bdbfeada7217ad8a4cbbe45b9d6bdd4b62abbca4c6f6", size = 40125195 },
-    { url = "https://files.pythonhosted.org/packages/83/88/1938d783727db1b178ff71bc6a6143d7939e406db83a9ec23cad3dad325c/pyarrow-18.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:01c034b576ce0eef554f7c3d8c341714954be9b3f5d5bc7117006b85fcf302fe", size = 38641884 },
-    { url = "https://files.pythonhosted.org/packages/5e/b5/9e14e9f7590e0eaa435ecea84dabb137284a4dbba7b3c337b58b65b76d95/pyarrow-18.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:f266a2c0fc31995a06ebd30bcfdb7f615d7278035ec5b1cd71c48d56daaf30b0", size = 40076877 },
-    { url = "https://files.pythonhosted.org/packages/4d/a3/817ac7fe0891a2d66e247e223080f3a6a262d8aefd77e11e8c27e6acf4e1/pyarrow-18.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:d4f13eee18433f99adefaeb7e01d83b59f73360c231d4782d9ddfaf1c3fbde0a", size = 25119811 },
-    { url = "https://files.pythonhosted.org/packages/6a/50/12829e7111b932581e51dda51d5cb39207a056c30fe31ef43f14c63c4d7e/pyarrow-18.1.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:9f3a76670b263dc41d0ae877f09124ab96ce10e4e48f3e3e4257273cee61ad0d", size = 29514620 },
-    { url = "https://files.pythonhosted.org/packages/d1/41/468c944eab157702e96abab3d07b48b8424927d4933541ab43788bb6964d/pyarrow-18.1.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:da31fbca07c435be88a0c321402c4e31a2ba61593ec7473630769de8346b54ee", size = 30856494 },
-    { url = "https://files.pythonhosted.org/packages/68/f9/29fb659b390312a7345aeb858a9d9c157552a8852522f2c8bad437c29c0a/pyarrow-18.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:543ad8459bc438efc46d29a759e1079436290bd583141384c6f7a1068ed6f992", size = 39203624 },
-    { url = "https://files.pythonhosted.org/packages/6e/f6/19360dae44200e35753c5c2889dc478154cd78e61b1f738514c9f131734d/pyarrow-18.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0743e503c55be0fdb5c08e7d44853da27f19dc854531c0570f9f394ec9671d54", size = 40139341 },
-    { url = "https://files.pythonhosted.org/packages/bb/e6/9b3afbbcf10cc724312e824af94a2e993d8ace22994d823f5c35324cebf5/pyarrow-18.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d4b3d2a34780645bed6414e22dda55a92e0fcd1b8a637fba86800ad737057e33", size = 38618629 },
-    { url = "https://files.pythonhosted.org/packages/3a/2e/3b99f8a3d9e0ccae0e961978a0d0089b25fb46ebbcfb5ebae3cca179a5b3/pyarrow-18.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c52f81aa6f6575058d8e2c782bf79d4f9fdc89887f16825ec3a66607a5dd8e30", size = 40078661 },
-    { url = "https://files.pythonhosted.org/packages/76/52/f8da04195000099d394012b8d42c503d7041b79f778d854f410e5f05049a/pyarrow-18.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:0ad4892617e1a6c7a551cfc827e072a633eaff758fa09f21c4ee548c30bcaf99", size = 25092330 },
-    { url = "https://files.pythonhosted.org/packages/cb/87/aa4d249732edef6ad88899399047d7e49311a55749d3c373007d034ee471/pyarrow-18.1.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:84e314d22231357d473eabec709d0ba285fa706a72377f9cc8e1cb3c8013813b", size = 29497406 },
-    { url = "https://files.pythonhosted.org/packages/3c/c7/ed6adb46d93a3177540e228b5ca30d99fc8ea3b13bdb88b6f8b6467e2cb7/pyarrow-18.1.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:f591704ac05dfd0477bb8f8e0bd4b5dc52c1cadf50503858dce3a15db6e46ff2", size = 30835095 },
-    { url = "https://files.pythonhosted.org/packages/41/d7/ed85001edfb96200ff606943cff71d64f91926ab42828676c0fc0db98963/pyarrow-18.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acb7564204d3c40babf93a05624fc6a8ec1ab1def295c363afc40b0c9e66c191", size = 39194527 },
-    { url = "https://files.pythonhosted.org/packages/59/16/35e28eab126342fa391593415d79477e89582de411bb95232f28b131a769/pyarrow-18.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74de649d1d2ccb778f7c3afff6085bd5092aed4c23df9feeb45dd6b16f3811aa", size = 40131443 },
-    { url = "https://files.pythonhosted.org/packages/0c/95/e855880614c8da20f4cd74fa85d7268c725cf0013dc754048593a38896a0/pyarrow-18.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:f96bd502cb11abb08efea6dab09c003305161cb6c9eafd432e35e76e7fa9b90c", size = 38608750 },
-    { url = "https://files.pythonhosted.org/packages/54/9d/f253554b1457d4fdb3831b7bd5f8f00f1795585a606eabf6fec0a58a9c38/pyarrow-18.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:36ac22d7782554754a3b50201b607d553a8d71b78cdf03b33c1125be4b52397c", size = 40066690 },
-    { url = "https://files.pythonhosted.org/packages/2f/58/8912a2563e6b8273e8aa7b605a345bba5a06204549826f6493065575ebc0/pyarrow-18.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:25dbacab8c5952df0ca6ca0af28f50d45bd31c1ff6fcf79e2d120b4a65ee7181", size = 25081054 },
-    { url = "https://files.pythonhosted.org/packages/82/f9/d06ddc06cab1ada0c2f2fd205ac8c25c2701182de1b9c4bf7a0a44844431/pyarrow-18.1.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6a276190309aba7bc9d5bd2933230458b3521a4317acfefe69a354f2fe59f2bc", size = 29525542 },
-    { url = "https://files.pythonhosted.org/packages/ab/94/8917e3b961810587ecbdaa417f8ebac0abb25105ae667b7aa11c05876976/pyarrow-18.1.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:ad514dbfcffe30124ce655d72771ae070f30bf850b48bc4d9d3b25993ee0e386", size = 30829412 },
-    { url = "https://files.pythonhosted.org/packages/5e/e3/3b16c3190f3d71d3b10f6758d2d5f7779ef008c4fd367cedab3ed178a9f7/pyarrow-18.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aebc13a11ed3032d8dd6e7171eb6e86d40d67a5639d96c35142bd568b9299324", size = 39119106 },
-    { url = "https://files.pythonhosted.org/packages/1d/d6/5d704b0d25c3c79532f8c0639f253ec2803b897100f64bcb3f53ced236e5/pyarrow-18.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6cf5c05f3cee251d80e98726b5c7cc9f21bab9e9783673bac58e6dfab57ecc8", size = 40090940 },
-    { url = "https://files.pythonhosted.org/packages/37/29/366bc7e588220d74ec00e497ac6710c2833c9176f0372fe0286929b2d64c/pyarrow-18.1.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:11b676cd410cf162d3f6a70b43fb9e1e40affbc542a1e9ed3681895f2962d3d9", size = 38548177 },
-    { url = "https://files.pythonhosted.org/packages/c8/11/fabf6ecabb1fe5b7d96889228ca2a9158c4c3bb732e3b8ee3f7f6d40b703/pyarrow-18.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:b76130d835261b38f14fc41fdfb39ad8d672afb84c447126b84d5472244cfaba", size = 40043567 },
+version = "19.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/7b/01/fe1fd04744c2aa038e5a11c7a4adb3d62bce09798695e54f7274b5977134/pyarrow-19.0.0.tar.gz", hash = "sha256:8d47c691765cf497aaeed4954d226568563f1b3b74ff61139f2d77876717084b", size = 1129096 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/82/42/fba3a35bef5833bf88ed35e6a810dc1781236e1d4f808d2df824a7d21819/pyarrow-19.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8e3a839bf36ec03b4315dc924d36dcde5444a50066f1c10f8290293c0427b46a", size = 30711936 },
+    { url = "https://files.pythonhosted.org/packages/88/7a/0da93a3eaaf251a30e32f3221e874263cdcd366c2cd6b7c05293aad91152/pyarrow-19.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:ce42275097512d9e4e4a39aade58ef2b3798a93aa3026566b7892177c266f735", size = 32133182 },
+    { url = "https://files.pythonhosted.org/packages/2f/df/fe43b1c50d3100d0de53f988344118bc20362d0de005f8a407454fa565f8/pyarrow-19.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9348a0137568c45601b031a8d118275069435f151cbb77e6a08a27e8125f59d4", size = 41145489 },
+    { url = "https://files.pythonhosted.org/packages/45/bb/6f73b41b342a0342f2516a02db4aa97a4f9569cc35482a5c288090140cd4/pyarrow-19.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a0144a712d990d60f7f42b7a31f0acaccf4c1e43e957f7b1ad58150d6f639c1", size = 42177823 },
+    { url = "https://files.pythonhosted.org/packages/23/7b/f038a96f421e453a71bd7a0f78d62b1b2ae9bcac06ed51179ca532e6a0a2/pyarrow-19.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2a1a109dfda558eb011e5f6385837daffd920d54ca00669f7a11132d0b1e6042", size = 40530609 },
+    { url = "https://files.pythonhosted.org/packages/b8/39/a2a6714b471c000e6dd6af4495dce00d7d1332351b8e3170dfb9f91dad1f/pyarrow-19.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:be686bf625aa7b9bada18defb3a3ea3981c1099697239788ff111d87f04cd263", size = 42081534 },
+    { url = "https://files.pythonhosted.org/packages/6c/a3/8396fb06ca05d807e89980c177be26617aad15211ece3184e0caa730b8a6/pyarrow-19.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:239ca66d9a05844bdf5af128861af525e14df3c9591bcc05bac25918e650d3a2", size = 25281090 },
+    { url = "https://files.pythonhosted.org/packages/bc/2e/152885f5ef421e80dae68b9c133ab261934f93a6d5e16b61d79c0ed597fb/pyarrow-19.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:a7bbe7109ab6198688b7079cbad5a8c22de4d47c4880d8e4847520a83b0d1b68", size = 30667964 },
+    { url = "https://files.pythonhosted.org/packages/80/c2/08bbee9a8610a47c9a1466845f405baf53a639ddd947c5133d8ba13544b6/pyarrow-19.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:4624c89d6f777c580e8732c27bb8e77fd1433b89707f17c04af7635dd9638351", size = 32125039 },
+    { url = "https://files.pythonhosted.org/packages/d2/56/06994df823212f5688d3c8bf4294928b12c9be36681872853655724d28c6/pyarrow-19.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b6d3ce4288793350dc2d08d1e184fd70631ea22a4ff9ea5c4ff182130249d9b", size = 41140729 },
+    { url = "https://files.pythonhosted.org/packages/94/65/38ad577c98140a9db71e9e1e594b6adb58a7478a5afec6456a8ca2df7f70/pyarrow-19.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:450a7d27e840e4d9a384b5c77199d489b401529e75a3b7a3799d4cd7957f2f9c", size = 42202267 },
+    { url = "https://files.pythonhosted.org/packages/b6/1f/966b722251a7354114ccbb71cf1a83922023e69efd8945ebf628a851ec4c/pyarrow-19.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:a08e2a8a039a3f72afb67a6668180f09fddaa38fe0d21f13212b4aba4b5d2451", size = 40505858 },
+    { url = "https://files.pythonhosted.org/packages/3b/5e/6bc81aa7fc9affc7d1c03b912fbcc984ca56c2a18513684da267715dab7b/pyarrow-19.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:f43f5aef2a13d4d56adadae5720d1fed4c1356c993eda8b59dace4b5983843c1", size = 42084973 },
+    { url = "https://files.pythonhosted.org/packages/53/c3/2f56da818b6a4758cbd514957c67bd0f078ebffa5390ee2e2bf0f9e8defc/pyarrow-19.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:2f672f5364b2d7829ef7c94be199bb88bf5661dd485e21d2d37de12ccb78a136", size = 25241976 },
 ]
 
 [[package]]
@@ -1680,16 +1515,16 @@ wheels = [
 
 [[package]]
 name = "pydantic"
-version = "2.10.4"
+version = "2.10.6"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "annotated-types" },
     { name = "pydantic-core" },
     { name = "typing-extensions" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/70/7e/fb60e6fee04d0ef8f15e4e01ff187a196fa976eb0f0ab524af4599e5754c/pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06", size = 762094 }
+sdist = { url = "https://files.pythonhosted.org/packages/b7/ae/d5220c5c52b158b1de7ca89fc5edb72f304a70a4c540c84c8844bf4008de/pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236", size = 761681 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/f3/26/3e1bbe954fde7ee22a6e7d31582c642aad9e84ffe4b5fb61e63b87cd326f/pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", size = 431765 },
+    { url = "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", size = 431696 },
 ]
 
 [[package]]
@@ -1729,20 +1564,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064 },
     { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046 },
     { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092 },
-    { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709 },
-    { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273 },
-    { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027 },
-    { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888 },
-    { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738 },
-    { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138 },
-    { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025 },
-    { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633 },
-    { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404 },
-    { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130 },
-    { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946 },
-    { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387 },
-    { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453 },
-    { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 },
 ]
 
 [[package]]
@@ -1760,14 +1581,14 @@ wheels = [
 
 [[package]]
 name = "pyee"
-version = "12.0.0"
+version = "12.1.1"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "typing-extensions" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/d2/a7/8faaa62a488a2a1e0d56969757f087cbd2729e9bcfa508c230299f366b4c/pyee-12.0.0.tar.gz", hash = "sha256:c480603f4aa2927d4766eb41fa82793fe60a82cbfdb8d688e0d08c55a534e145", size = 29675 }
+sdist = { url = "https://files.pythonhosted.org/packages/0a/37/8fb6e653597b2b67ef552ed49b438d5398ba3b85a9453f8ada0fd77d455c/pyee-12.1.1.tar.gz", hash = "sha256:bbc33c09e2ff827f74191e3e5bbc6be7da02f627b7ec30d86f5ce1a6fb2424a3", size = 30915 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/1d/0d/95993c08c721ec68892547f2117e8f9dfbcef2ca71e098533541b4a54d5f/pyee-12.0.0-py3-none-any.whl", hash = "sha256:7b14b74320600049ccc7d0e0b1becd3b4bd0a03c745758225e31a59f4095c990", size = 14831 },
+    { url = "https://files.pythonhosted.org/packages/25/68/7e150cba9eeffdeb3c5cecdb6896d70c8edd46ce41c0491e12fb2b2256ff/pyee-12.1.1-py3-none-any.whl", hash = "sha256:18a19c650556bb6b32b406d7f017c8f513aceed1ef7ca618fb65de7bd2d347ef", size = 15527 },
 ]
 
 [[package]]
@@ -1828,14 +1649,14 @@ wheels = [
 
 [[package]]
 name = "pytest-asyncio"
-version = "0.25.1"
+version = "0.25.3"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "pytest" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/4b/04/0477a4bdd176ad678d148c075f43620b3f7a060ff61c7da48500b1fa8a75/pytest_asyncio-0.25.1.tar.gz", hash = "sha256:79be8a72384b0c917677e00daa711e07db15259f4d23203c59012bcd989d4aee", size = 53760 }
+sdist = { url = "https://files.pythonhosted.org/packages/f2/a8/ecbc8ede70921dd2f544ab1cadd3ff3bf842af27f87bbdea774c7baa1d38/pytest_asyncio-0.25.3.tar.gz", hash = "sha256:fc1da2cf9f125ada7e710b4ddad05518d4cee187ae9412e9ac9271003497f07a", size = 54239 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/81/fb/efc7226b384befd98d0e00d8c4390ad57f33c8fde00094b85c5e07897def/pytest_asyncio-0.25.1-py3-none-any.whl", hash = "sha256:c84878849ec63ff2ca509423616e071ef9cd8cc93c053aa33b5b8fb70a990671", size = 19357 },
+    { url = "https://files.pythonhosted.org/packages/67/17/3493c5624e48fd97156ebaec380dcaafee9506d7e2c46218ceebbb57d7de/pytest_asyncio-0.25.3-py3-none-any.whl", hash = "sha256:9e89518e0f9bd08928f97a3482fdc4e244df17529460bc038291ccaf8f85c7c3", size = 19467 },
 ]
 
 [[package]]
@@ -1866,7 +1687,7 @@ wheels = [
 
 [[package]]
 name = "pytest-playwright"
-version = "0.6.2"
+version = "0.7.0"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "playwright" },
@@ -1874,9 +1695,9 @@ dependencies = [
     { name = "pytest-base-url" },
     { name = "python-slugify" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/a7/19/ae0252d2c36f518733cca294bfcd41c18dad32c2d8aff424d6d1531f1827/pytest_playwright-0.6.2.tar.gz", hash = "sha256:ff4054b19aa05df096ac6f74f0572591566aaf0f6d97f6cb9674db8a4d4ed06c", size = 16293 }
+sdist = { url = "https://files.pythonhosted.org/packages/e3/47/38e292ad92134a00ea05e6fc4fc44577baaa38b0922ab7ea56312b7a6663/pytest_playwright-0.7.0.tar.gz", hash = "sha256:b3f2ea514bbead96d26376fac182f68dcd6571e7cb41680a89ff1673c05d60b6", size = 16666 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/72/38/e95090d0a26114a650f7d8847425f21757fc740de965df94de47b439fe67/pytest_playwright-0.6.2-py3-none-any.whl", hash = "sha256:0eff73bebe497b0158befed91e2f5fe94cfa17181f8b3acf575beed84e7e9043", size = 16436 },
+    { url = "https://files.pythonhosted.org/packages/d8/96/5f8a4545d783674f3de33f0ebc4db16cc76ce77a4c404d284f43f09125e3/pytest_playwright-0.7.0-py3-none-any.whl", hash = "sha256:2516d0871fa606634bfe32afbcc0342d68da2dbff97fe3459849e9c428486da2", size = 16618 },
 ]
 
 [[package]]
@@ -2008,28 +1829,20 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 },
     { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 },
     { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 },
-    { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 },
-    { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 },
-    { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 },
-    { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 },
-    { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 },
-    { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 },
-    { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 },
-    { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 },
-    { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 },
 ]
 
 [[package]]
 name = "referencing"
-version = "0.35.1"
+version = "0.36.2"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "attrs" },
     { name = "rpds-py" },
+    { name = "typing-extensions" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/99/5b/73ca1f8e72fff6fa52119dbd185f73a907b1989428917b24cff660129b6d/referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", size = 62991 }
+sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/b7/59/2056f61236782a2c86b33906c025d4f4a0b17be0161b63b70fd9e8775d36/referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de", size = 26684 },
+    { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775 },
 ]
 
 [[package]]
@@ -2104,69 +1917,43 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/09/42/cacaeb047a22cab6241f107644f230e2935d4efecf6488859a7dd82fc47d/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7", size = 555953 },
     { url = "https://files.pythonhosted.org/packages/e6/52/c921dc6d5f5d45b212a456c1f5b17df1a471127e8037eb0972379e39dff4/rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627", size = 221339 },
     { url = "https://files.pythonhosted.org/packages/f2/c7/f82b5be1e8456600395366f86104d1bd8d0faed3802ad511ef6d60c30d98/rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4", size = 235786 },
-    { url = "https://files.pythonhosted.org/packages/d0/bf/36d5cc1f2c609ae6e8bf0fc35949355ca9d8790eceb66e6385680c951e60/rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84", size = 351657 },
-    { url = "https://files.pythonhosted.org/packages/24/2a/f1e0fa124e300c26ea9382e59b2d582cba71cedd340f32d1447f4f29fa4e/rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25", size = 341829 },
-    { url = "https://files.pythonhosted.org/packages/cf/c2/0da1231dd16953845bed60d1a586fcd6b15ceaeb965f4d35cdc71f70f606/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4", size = 384220 },
-    { url = "https://files.pythonhosted.org/packages/c7/73/a4407f4e3a00a9d4b68c532bf2d873d6b562854a8eaff8faa6133b3588ec/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5", size = 391009 },
-    { url = "https://files.pythonhosted.org/packages/a9/c3/04b7353477ab360fe2563f5f0b176d2105982f97cd9ae80a9c5a18f1ae0f/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc", size = 426989 },
-    { url = "https://files.pythonhosted.org/packages/8d/e6/e4b85b722bcf11398e17d59c0f6049d19cd606d35363221951e6d625fcb0/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b", size = 441544 },
-    { url = "https://files.pythonhosted.org/packages/27/fc/403e65e56f65fff25f2973216974976d3f0a5c3f30e53758589b6dc9b79b/rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518", size = 385179 },
-    { url = "https://files.pythonhosted.org/packages/57/9b/2be9ff9700d664d51fd96b33d6595791c496d2778cb0b2a634f048437a55/rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd", size = 415103 },
-    { url = "https://files.pythonhosted.org/packages/bb/a5/03c2ad8ca10994fcf22dd2150dd1d653bc974fa82d9a590494c84c10c641/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2", size = 560916 },
-    { url = "https://files.pythonhosted.org/packages/ba/2e/be4fdfc8b5b576e588782b56978c5b702c5a2307024120d8aeec1ab818f0/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16", size = 587062 },
-    { url = "https://files.pythonhosted.org/packages/67/e0/2034c221937709bf9c542603d25ad43a68b4b0a9a0c0b06a742f2756eb66/rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f", size = 555734 },
-    { url = "https://files.pythonhosted.org/packages/ea/ce/240bae07b5401a22482b58e18cfbabaa392409b2797da60223cca10d7367/rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de", size = 220663 },
-    { url = "https://files.pythonhosted.org/packages/cb/f0/d330d08f51126330467edae2fa4efa5cec8923c87551a79299380fdea30d/rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9", size = 235503 },
-    { url = "https://files.pythonhosted.org/packages/f7/c4/dbe1cc03df013bf2feb5ad00615038050e7859f381e96fb5b7b4572cd814/rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b", size = 347698 },
-    { url = "https://files.pythonhosted.org/packages/a4/3a/684f66dd6b0f37499cad24cd1c0e523541fd768576fa5ce2d0a8799c3cba/rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b", size = 337330 },
-    { url = "https://files.pythonhosted.org/packages/82/eb/e022c08c2ce2e8f7683baa313476492c0e2c1ca97227fe8a75d9f0181e95/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1", size = 380022 },
-    { url = "https://files.pythonhosted.org/packages/e4/21/5a80e653e4c86aeb28eb4fea4add1f72e1787a3299687a9187105c3ee966/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83", size = 390754 },
-    { url = "https://files.pythonhosted.org/packages/37/a4/d320a04ae90f72d080b3d74597074e62be0a8ecad7d7321312dfe2dc5a6a/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd", size = 423840 },
-    { url = "https://files.pythonhosted.org/packages/87/70/674dc47d93db30a6624279284e5631be4c3a12a0340e8e4f349153546728/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1", size = 438970 },
-    { url = "https://files.pythonhosted.org/packages/3f/64/9500f4d66601d55cadd21e90784cfd5d5f4560e129d72e4339823129171c/rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3", size = 383146 },
-    { url = "https://files.pythonhosted.org/packages/4d/45/630327addb1d17173adcf4af01336fd0ee030c04798027dfcb50106001e0/rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130", size = 408294 },
-    { url = "https://files.pythonhosted.org/packages/5f/ef/8efb3373cee54ea9d9980b772e5690a0c9e9214045a4e7fa35046e399fee/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c", size = 556345 },
-    { url = "https://files.pythonhosted.org/packages/54/01/151d3b9ef4925fc8f15bfb131086c12ec3c3d6dd4a4f7589c335bf8e85ba/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b", size = 582292 },
-    { url = "https://files.pythonhosted.org/packages/30/89/35fc7a6cdf3477d441c7aca5e9bbf5a14e0f25152aed7f63f4e0b141045d/rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333", size = 553855 },
-    { url = "https://files.pythonhosted.org/packages/8f/e0/830c02b2457c4bd20a8c5bb394d31d81f57fbefce2dbdd2e31feff4f7003/rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730", size = 219100 },
-    { url = "https://files.pythonhosted.org/packages/f8/30/7ac943f69855c2db77407ae363484b915d861702dbba1aa82d68d57f42be/rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf", size = 233794 },
 ]
 
 [[package]]
 name = "ruff"
-version = "0.8.6"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/da/00/089db7890ea3be5709e3ece6e46408d6f1e876026ec3fd081ee585fef209/ruff-0.8.6.tar.gz", hash = "sha256:dcad24b81b62650b0eb8814f576fc65cfee8674772a6e24c9b747911801eeaa5", size = 3473116 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/d7/28/aa07903694637c2fa394a9f4fe93cf861ad8b09f1282fa650ef07ff9fe97/ruff-0.8.6-py3-none-linux_armv6l.whl", hash = "sha256:defed167955d42c68b407e8f2e6f56ba52520e790aba4ca707a9c88619e580e3", size = 10628735 },
-    { url = "https://files.pythonhosted.org/packages/2b/43/827bb1448f1fcb0fb42e9c6edf8fb067ca8244923bf0ddf12b7bf949065c/ruff-0.8.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:54799ca3d67ae5e0b7a7ac234baa657a9c1784b48ec954a094da7c206e0365b1", size = 10386758 },
-    { url = "https://files.pythonhosted.org/packages/df/93/fc852a81c3cd315b14676db3b8327d2bb2d7508649ad60bfdb966d60738d/ruff-0.8.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e88b8f6d901477c41559ba540beeb5a671e14cd29ebd5683903572f4b40a9807", size = 10007808 },
-    { url = "https://files.pythonhosted.org/packages/94/e9/e0ed4af1794335fb280c4fac180f2bf40f6a3b859cae93a5a3ada27325ae/ruff-0.8.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0509e8da430228236a18a677fcdb0c1f102dd26d5520f71f79b094963322ed25", size = 10861031 },
-    { url = "https://files.pythonhosted.org/packages/82/68/da0db02f5ecb2ce912c2bef2aa9fcb8915c31e9bc363969cfaaddbc4c1c2/ruff-0.8.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91a7ddb221779871cf226100e677b5ea38c2d54e9e2c8ed847450ebbdf99b32d", size = 10388246 },
-    { url = "https://files.pythonhosted.org/packages/ac/1d/b85383db181639019b50eb277c2ee48f9f5168f4f7c287376f2b6e2a6dc2/ruff-0.8.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:248b1fb3f739d01d528cc50b35ee9c4812aa58cc5935998e776bf8ed5b251e75", size = 11424693 },
-    { url = "https://files.pythonhosted.org/packages/ac/b7/30bc78a37648d31bfc7ba7105b108cb9091cd925f249aa533038ebc5a96f/ruff-0.8.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:bc3c083c50390cf69e7e1b5a5a7303898966be973664ec0c4a4acea82c1d4315", size = 12141921 },
-    { url = "https://files.pythonhosted.org/packages/60/b3/ee0a14cf6a1fbd6965b601c88d5625d250b97caf0534181e151504498f86/ruff-0.8.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52d587092ab8df308635762386f45f4638badb0866355b2b86760f6d3c076188", size = 11692419 },
-    { url = "https://files.pythonhosted.org/packages/ef/d6/c597062b2931ba3e3861e80bd2b147ca12b3370afc3889af46f29209037f/ruff-0.8.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:61323159cf21bc3897674e5adb27cd9e7700bab6b84de40d7be28c3d46dc67cf", size = 12981648 },
-    { url = "https://files.pythonhosted.org/packages/68/84/21f578c2a4144917985f1f4011171aeff94ab18dfa5303ac632da2f9af36/ruff-0.8.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ae4478b1471fc0c44ed52a6fb787e641a2ac58b1c1f91763bafbc2faddc5117", size = 11251801 },
-    { url = "https://files.pythonhosted.org/packages/6c/aa/1ac02537c8edeb13e0955b5db86b5c050a1dcba54f6d49ab567decaa59c1/ruff-0.8.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0c000a471d519b3e6cfc9c6680025d923b4ca140ce3e4612d1a2ef58e11f11fe", size = 10849857 },
-    { url = "https://files.pythonhosted.org/packages/eb/00/020cb222252d833956cb3b07e0e40c9d4b984fbb2dc3923075c8f944497d/ruff-0.8.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9257aa841e9e8d9b727423086f0fa9a86b6b420fbf4bf9e1465d1250ce8e4d8d", size = 10470852 },
-    { url = "https://files.pythonhosted.org/packages/00/56/e6d6578202a0141cd52299fe5acb38b2d873565f4670c7a5373b637cf58d/ruff-0.8.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:45a56f61b24682f6f6709636949ae8cc82ae229d8d773b4c76c09ec83964a95a", size = 10972997 },
-    { url = "https://files.pythonhosted.org/packages/be/31/dd0db1f4796bda30dea7592f106f3a67a8f00bcd3a50df889fbac58e2786/ruff-0.8.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:496dd38a53aa173481a7d8866bcd6451bd934d06976a2505028a50583e001b76", size = 11317760 },
-    { url = "https://files.pythonhosted.org/packages/d4/70/cfcb693dc294e034c6fed837fa2ec98b27cc97a26db5d049345364f504bf/ruff-0.8.6-py3-none-win32.whl", hash = "sha256:e169ea1b9eae61c99b257dc83b9ee6c76f89042752cb2d83486a7d6e48e8f764", size = 8799729 },
-    { url = "https://files.pythonhosted.org/packages/60/22/ae6bcaa0edc83af42751bd193138bfb7598b2990939d3e40494d6c00698c/ruff-0.8.6-py3-none-win_amd64.whl", hash = "sha256:f1d70bef3d16fdc897ee290d7d20da3cbe4e26349f62e8a0274e7a3f4ce7a905", size = 9673857 },
-    { url = "https://files.pythonhosted.org/packages/91/f8/3765e053acd07baa055c96b2065c7fab91f911b3c076dfea71006666f5b0/ruff-0.8.6-py3-none-win_arm64.whl", hash = "sha256:7d7fc2377a04b6e04ffe588caad613d0c460eb2ecba4c0ccbbfe2bc973cbc162", size = 9149556 },
+version = "0.9.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/2a/e1/e265aba384343dd8ddd3083f5e33536cd17e1566c41453a5517b5dd443be/ruff-0.9.6.tar.gz", hash = "sha256:81761592f72b620ec8fa1068a6fd00e98a5ebee342a3642efd84454f3031dca9", size = 3639454 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/76/e3/3d2c022e687e18cf5d93d6bfa2722d46afc64eaa438c7fbbdd603b3597be/ruff-0.9.6-py3-none-linux_armv6l.whl", hash = "sha256:2f218f356dd2d995839f1941322ff021c72a492c470f0b26a34f844c29cdf5ba", size = 11714128 },
+    { url = "https://files.pythonhosted.org/packages/e1/22/aff073b70f95c052e5c58153cba735748c9e70107a77d03420d7850710a0/ruff-0.9.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b908ff4df65dad7b251c9968a2e4560836d8f5487c2f0cc238321ed951ea0504", size = 11682539 },
+    { url = "https://files.pythonhosted.org/packages/75/a7/f5b7390afd98a7918582a3d256cd3e78ba0a26165a467c1820084587cbf9/ruff-0.9.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b109c0ad2ececf42e75fa99dc4043ff72a357436bb171900714a9ea581ddef83", size = 11132512 },
+    { url = "https://files.pythonhosted.org/packages/a6/e3/45de13ef65047fea2e33f7e573d848206e15c715e5cd56095589a7733d04/ruff-0.9.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1de4367cca3dac99bcbd15c161404e849bb0bfd543664db39232648dc00112dc", size = 11929275 },
+    { url = "https://files.pythonhosted.org/packages/7d/f2/23d04cd6c43b2e641ab961ade8d0b5edb212ecebd112506188c91f2a6e6c/ruff-0.9.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac3ee4d7c2c92ddfdaedf0bf31b2b176fa7aa8950efc454628d477394d35638b", size = 11466502 },
+    { url = "https://files.pythonhosted.org/packages/b5/6f/3a8cf166f2d7f1627dd2201e6cbc4cb81f8b7d58099348f0c1ff7b733792/ruff-0.9.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dc1edd1775270e6aa2386119aea692039781429f0be1e0949ea5884e011aa8e", size = 12676364 },
+    { url = "https://files.pythonhosted.org/packages/f5/c4/db52e2189983c70114ff2b7e3997e48c8318af44fe83e1ce9517570a50c6/ruff-0.9.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4a091729086dffa4bd070aa5dab7e39cc6b9d62eb2bef8f3d91172d30d599666", size = 13335518 },
+    { url = "https://files.pythonhosted.org/packages/66/44/545f8a4d136830f08f4d24324e7db957c5374bf3a3f7a6c0bc7be4623a37/ruff-0.9.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1bbc6808bf7b15796cef0815e1dfb796fbd383e7dbd4334709642649625e7c5", size = 12823287 },
+    { url = "https://files.pythonhosted.org/packages/c5/26/8208ef9ee7431032c143649a9967c3ae1aae4257d95e6f8519f07309aa66/ruff-0.9.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:589d1d9f25b5754ff230dce914a174a7c951a85a4e9270613a2b74231fdac2f5", size = 14592374 },
+    { url = "https://files.pythonhosted.org/packages/31/70/e917781e55ff39c5b5208bda384fd397ffd76605e68544d71a7e40944945/ruff-0.9.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc61dd5131742e21103fbbdcad683a8813be0e3c204472d520d9a5021ca8b217", size = 12500173 },
+    { url = "https://files.pythonhosted.org/packages/84/f5/e4ddee07660f5a9622a9c2b639afd8f3104988dc4f6ba0b73ffacffa9a8c/ruff-0.9.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5e2d9126161d0357e5c8f30b0bd6168d2c3872372f14481136d13de9937f79b6", size = 11906555 },
+    { url = "https://files.pythonhosted.org/packages/f1/2b/6ff2fe383667075eef8656b9892e73dd9b119b5e3add51298628b87f6429/ruff-0.9.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:68660eab1a8e65babb5229a1f97b46e3120923757a68b5413d8561f8a85d4897", size = 11538958 },
+    { url = "https://files.pythonhosted.org/packages/3c/db/98e59e90de45d1eb46649151c10a062d5707b5b7f76f64eb1e29edf6ebb1/ruff-0.9.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:c4cae6c4cc7b9b4017c71114115db0445b00a16de3bcde0946273e8392856f08", size = 12117247 },
+    { url = "https://files.pythonhosted.org/packages/ec/bc/54e38f6d219013a9204a5a2015c09e7a8c36cedcd50a4b01ac69a550b9d9/ruff-0.9.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:19f505b643228b417c1111a2a536424ddde0db4ef9023b9e04a46ed8a1cb4656", size = 12554647 },
+    { url = "https://files.pythonhosted.org/packages/a5/7d/7b461ab0e2404293c0627125bb70ac642c2e8d55bf590f6fce85f508f1b2/ruff-0.9.6-py3-none-win32.whl", hash = "sha256:194d8402bceef1b31164909540a597e0d913c0e4952015a5b40e28c146121b5d", size = 9949214 },
+    { url = "https://files.pythonhosted.org/packages/ee/30/c3cee10f915ed75a5c29c1e57311282d1a15855551a64795c1b2bbe5cf37/ruff-0.9.6-py3-none-win_amd64.whl", hash = "sha256:03482d5c09d90d4ee3f40d97578423698ad895c87314c4de39ed2af945633caa", size = 10999914 },
+    { url = "https://files.pythonhosted.org/packages/e8/a8/d71f44b93e3aa86ae232af1f2126ca7b95c0f515ec135462b3e1f351441c/ruff-0.9.6-py3-none-win_arm64.whl", hash = "sha256:0e2bb706a2be7ddfea4a4af918562fdc1bcb16df255e5fa595bbd800ce322a5a", size = 10177499 },
 ]
 
 [[package]]
 name = "s3transfer"
-version = "0.10.4"
+version = "0.11.2"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "botocore" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/c0/0a/1cdbabf9edd0ea7747efdf6c9ab4e7061b085aa7f9bfc36bb1601563b069/s3transfer-0.10.4.tar.gz", hash = "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7", size = 145287 }
+sdist = { url = "https://files.pythonhosted.org/packages/62/45/2323b5928f86fd29f9afdcef4659f68fa73eaa5356912b774227f5cf46b5/s3transfer-0.11.2.tar.gz", hash = "sha256:3b39185cb72f5acc77db1a58b6e25b977f28d20496b6e58d6813d75f464d632f", size = 147885 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/66/05/7957af15543b8c9799209506df4660cba7afc4cf94bfb60513827e96bed6/s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e", size = 83175 },
+    { url = "https://files.pythonhosted.org/packages/1b/ac/e7dc469e49048dc57f62e0c555d2ee3117fa30813d2a1a2962cce3a2a82a/s3transfer-0.11.2-py3-none-any.whl", hash = "sha256:be6ecb39fadd986ef1701097771f87e4d2f821f27f6071c872143884d2950fbc", size = 84151 },
 ]
 
 [[package]]
@@ -2197,7 +1984,7 @@ wheels = [
 
 [package.optional-dependencies]
 db = [
-    { name = "alembic" },
+    { name = "alembic", extra = ["tz"] },
     { name = "asyncpg" },
     { name = "sqlalchemy", extra = ["asyncio"] },
 ]
@@ -2214,6 +2001,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/1b/59/5e7d0affae5f34c114a5a887ebf4ce3e6d443f583df0b3d69b23cec9ea65/safir_logging-6.5.1-py3-none-any.whl", hash = "sha256:b056306de26627e29bd6a6d04b1144456a1319ec0e15a67ebbc12b43362a27cd", size = 9129 },
 ]
 
+[[package]]
+name = "setuptools"
+version = "75.8.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/92/ec/089608b791d210aec4e7f97488e67ab0d33add3efccb83a056cbafe3a2a6/setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6", size = 1343222 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/69/8a/b9dc7678803429e4a3bc9ba462fa3dd9066824d3c607490235c6a796be5a/setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3", size = 1228782 },
+]
+
 [[package]]
 name = "shellingham"
 version = "1.5.4"
@@ -2252,39 +2048,31 @@ wheels = [
 
 [[package]]
 name = "sqlalchemy"
-version = "2.0.36"
+version = "2.0.38"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "greenlet", marker = "(python_full_version < '3.13' and platform_machine == 'AMD64') or (python_full_version < '3.13' and platform_machine == 'WIN32') or (python_full_version < '3.13' and platform_machine == 'aarch64') or (python_full_version < '3.13' and platform_machine == 'amd64') or (python_full_version < '3.13' and platform_machine == 'ppc64le') or (python_full_version < '3.13' and platform_machine == 'win32') or (python_full_version < '3.13' and platform_machine == 'x86_64')" },
+    { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" },
     { name = "typing-extensions" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/50/65/9cbc9c4c3287bed2499e05033e207473504dc4df999ce49385fb1f8b058a/sqlalchemy-2.0.36.tar.gz", hash = "sha256:7f2767680b6d2398aea7082e45a774b2b0767b5c8d8ffb9c8b683088ea9b29c5", size = 9574485 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/00/4e/5a67963fd7cbc1beb8bd2152e907419f4c940ef04600b10151a751fe9e06/SQLAlchemy-2.0.36-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fd3a55deef00f689ce931d4d1b23fa9f04c880a48ee97af488fd215cf24e2a6c", size = 2093782 },
-    { url = "https://files.pythonhosted.org/packages/b3/24/30e33b6389ebb5a17df2a4243b091bc709fb3dfc9a48c8d72f8e037c943d/SQLAlchemy-2.0.36-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f5e9cd989b45b73bd359f693b935364f7e1f79486e29015813c338450aa5a71", size = 2084180 },
-    { url = "https://files.pythonhosted.org/packages/10/1e/70e9ed2143a27065246be40f78637ad5160ea0f5fd32f8cab819a31ff54d/SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ddd9db6e59c44875211bc4c7953a9f6638b937b0a88ae6d09eb46cced54eff", size = 3202469 },
-    { url = "https://files.pythonhosted.org/packages/b4/5f/95e0ed74093ac3c0db6acfa944d4d8ac6284ef5e1136b878a327ea1f975a/SQLAlchemy-2.0.36-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2519f3a5d0517fc159afab1015e54bb81b4406c278749779be57a569d8d1bb0d", size = 3202464 },
-    { url = "https://files.pythonhosted.org/packages/91/95/2cf9b85a6bc2ee660e40594dffe04e777e7b8617fd0c6d77a0f782ea96c9/SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:59b1ee96617135f6e1d6f275bbe988f419c5178016f3d41d3c0abb0c819f75bb", size = 3139508 },
-    { url = "https://files.pythonhosted.org/packages/92/ea/f0c01bc646456e4345c0fb5a3ddef457326285c2dc60435b0eb96b61bf31/SQLAlchemy-2.0.36-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:39769a115f730d683b0eb7b694db9789267bcd027326cccc3125e862eb03bfd8", size = 3159837 },
-    { url = "https://files.pythonhosted.org/packages/a6/93/c8edbf153ee38fe529773240877bf1332ed95328aceef6254288f446994e/SQLAlchemy-2.0.36-cp311-cp311-win32.whl", hash = "sha256:66bffbad8d6271bb1cc2f9a4ea4f86f80fe5e2e3e501a5ae2a3dc6a76e604e6f", size = 2064529 },
-    { url = "https://files.pythonhosted.org/packages/b1/03/d12b7c1d36fd80150c1d52e121614cf9377dac99e5497af8d8f5b2a8db64/SQLAlchemy-2.0.36-cp311-cp311-win_amd64.whl", hash = "sha256:23623166bfefe1487d81b698c423f8678e80df8b54614c2bf4b4cfcd7c711959", size = 2089874 },
-    { url = "https://files.pythonhosted.org/packages/b8/bf/005dc47f0e57556e14512d5542f3f183b94fde46e15ff1588ec58ca89555/SQLAlchemy-2.0.36-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7b64e6ec3f02c35647be6b4851008b26cff592a95ecb13b6788a54ef80bbdd4", size = 2092378 },
-    { url = "https://files.pythonhosted.org/packages/94/65/f109d5720779a08e6e324ec89a744f5f92c48bd8005edc814bf72fbb24e5/SQLAlchemy-2.0.36-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:46331b00096a6db1fdc052d55b101dbbfc99155a548e20a0e4a8e5e4d1362855", size = 2082778 },
-    { url = "https://files.pythonhosted.org/packages/60/f6/d9aa8c49c44f9b8c9b9dada1f12fa78df3d4c42aa2de437164b83ee1123c/SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdf3386a801ea5aba17c6410dd1dc8d39cf454ca2565541b5ac42a84e1e28f53", size = 3232191 },
-    { url = "https://files.pythonhosted.org/packages/8a/ab/81d4514527c068670cb1d7ab62a81a185df53a7c379bd2a5636e83d09ede/SQLAlchemy-2.0.36-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9dfa18ff2a67b09b372d5db8743c27966abf0e5344c555d86cc7199f7ad83a", size = 3243044 },
-    { url = "https://files.pythonhosted.org/packages/35/b4/f87c014ecf5167dc669199cafdb20a7358ff4b1d49ce3622cc48571f811c/SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:90812a8933df713fdf748b355527e3af257a11e415b613dd794512461eb8a686", size = 3178511 },
-    { url = "https://files.pythonhosted.org/packages/ea/09/badfc9293bc3ccba6ede05e5f2b44a760aa47d84da1fc5a326e963e3d4d9/SQLAlchemy-2.0.36-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1bc330d9d29c7f06f003ab10e1eaced295e87940405afe1b110f2eb93a233588", size = 3205147 },
-    { url = "https://files.pythonhosted.org/packages/c8/60/70e681de02a13c4b27979b7b78da3058c49bacc9858c89ba672e030f03f2/SQLAlchemy-2.0.36-cp312-cp312-win32.whl", hash = "sha256:79d2e78abc26d871875b419e1fd3c0bca31a1cb0043277d0d850014599626c2e", size = 2062709 },
-    { url = "https://files.pythonhosted.org/packages/b7/ed/f6cd9395e41bfe47dd253d74d2dfc3cab34980d4e20c8878cb1117306085/SQLAlchemy-2.0.36-cp312-cp312-win_amd64.whl", hash = "sha256:b544ad1935a8541d177cb402948b94e871067656b3a0b9e91dbec136b06a2ff5", size = 2088433 },
-    { url = "https://files.pythonhosted.org/packages/78/5c/236398ae3678b3237726819b484f15f5c038a9549da01703a771f05a00d6/SQLAlchemy-2.0.36-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b5cc79df7f4bc3d11e4b542596c03826063092611e481fcf1c9dfee3c94355ef", size = 2087651 },
-    { url = "https://files.pythonhosted.org/packages/a8/14/55c47420c0d23fb67a35af8be4719199b81c59f3084c28d131a7767b0b0b/SQLAlchemy-2.0.36-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3c01117dd36800f2ecaa238c65365b7b16497adc1522bf84906e5710ee9ba0e8", size = 2078132 },
-    { url = "https://files.pythonhosted.org/packages/3d/97/1e843b36abff8c4a7aa2e37f9bea364f90d021754c2de94d792c2d91405b/SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bc633f4ee4b4c46e7adcb3a9b5ec083bf1d9a97c1d3854b92749d935de40b9b", size = 3164559 },
-    { url = "https://files.pythonhosted.org/packages/7b/c5/07f18a897b997f6d6b234fab2bf31dccf66d5d16a79fe329aefc95cd7461/SQLAlchemy-2.0.36-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e46ed38affdfc95d2c958de328d037d87801cfcbea6d421000859e9789e61c2", size = 3177897 },
-    { url = "https://files.pythonhosted.org/packages/b3/cd/e16f3cbefd82b5c40b33732da634ec67a5f33b587744c7ab41699789d492/SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b2985c0b06e989c043f1dc09d4fe89e1616aadd35392aea2844f0458a989eacf", size = 3111289 },
-    { url = "https://files.pythonhosted.org/packages/15/85/5b8a3b0bc29c9928aa62b5c91fcc8335f57c1de0a6343873b5f372e3672b/SQLAlchemy-2.0.36-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a121d62ebe7d26fec9155f83f8be5189ef1405f5973ea4874a26fab9f1e262c", size = 3139491 },
-    { url = "https://files.pythonhosted.org/packages/a1/95/81babb6089938680dfe2cd3f88cd3fd39cccd1543b7cb603b21ad881bff1/SQLAlchemy-2.0.36-cp313-cp313-win32.whl", hash = "sha256:0572f4bd6f94752167adfd7c1bed84f4b240ee6203a95e05d1e208d488d0d436", size = 2060439 },
-    { url = "https://files.pythonhosted.org/packages/c1/ce/5f7428df55660d6879d0522adc73a3364970b5ef33ec17fa125c5dbcac1d/SQLAlchemy-2.0.36-cp313-cp313-win_amd64.whl", hash = "sha256:8c78ac40bde930c60e0f78b3cd184c580f89456dd87fc08f9e3ee3ce8765ce88", size = 2084574 },
-    { url = "https://files.pythonhosted.org/packages/b8/49/21633706dd6feb14cd3f7935fc00b60870ea057686035e1a99ae6d9d9d53/SQLAlchemy-2.0.36-py3-none-any.whl", hash = "sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e", size = 1883787 },
+sdist = { url = "https://files.pythonhosted.org/packages/e4/08/9a90962ea72acd532bda71249a626344d855c4032603924b1b547694b837/sqlalchemy-2.0.38.tar.gz", hash = "sha256:e5a4d82bdb4bf1ac1285a68eab02d253ab73355d9f0fe725a97e1e0fa689decb", size = 9634782 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/00/6c/9d3a638f297fce288ba12a4e5dbd08ef1841d119abee9300c100eba00217/SQLAlchemy-2.0.38-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bf89e0e4a30714b357f5d46b6f20e0099d38b30d45fa68ea48589faf5f12f62d", size = 2106330 },
+    { url = "https://files.pythonhosted.org/packages/0e/57/d5fdee56f418491267701965795805662b1744de40915d4764451390536d/SQLAlchemy-2.0.38-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8455aa60da49cb112df62b4721bd8ad3654a3a02b9452c783e651637a1f21fa2", size = 2096730 },
+    { url = "https://files.pythonhosted.org/packages/42/84/205f423f8b28329c47237b7e130a7f93c234a49fab20b4534bd1ff26a06a/SQLAlchemy-2.0.38-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f53c0d6a859b2db58332e0e6a921582a02c1677cc93d4cbb36fdf49709b327b2", size = 3215023 },
+    { url = "https://files.pythonhosted.org/packages/77/41/94a558d47bffae5a361b0cfb3721324ea4154829dd5432f80bd4cfeecbc9/SQLAlchemy-2.0.38-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3c4817dff8cef5697f5afe5fec6bc1783994d55a68391be24cb7d80d2dbc3a6", size = 3214991 },
+    { url = "https://files.pythonhosted.org/packages/74/a0/cc3c030e7440bd17ce67c1875f50edb41d0ef17b9c76fbc290ef27bbe37f/SQLAlchemy-2.0.38-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9cea5b756173bb86e2235f2f871b406a9b9d722417ae31e5391ccaef5348f2c", size = 3151854 },
+    { url = "https://files.pythonhosted.org/packages/24/ab/8ba2588c2eb1d092944551354d775ef4fc0250badede324d786a4395d10e/SQLAlchemy-2.0.38-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:40e9cdbd18c1f84631312b64993f7d755d85a3930252f6276a77432a2b25a2f3", size = 3172158 },
+    { url = "https://files.pythonhosted.org/packages/e0/73/2a3d6217e8e6abb553ed410ce5adc0bdec7effd684716f0fbaee5831d677/SQLAlchemy-2.0.38-cp311-cp311-win32.whl", hash = "sha256:cb39ed598aaf102251483f3e4675c5dd6b289c8142210ef76ba24aae0a8f8aba", size = 2076965 },
+    { url = "https://files.pythonhosted.org/packages/a4/17/364a99c8c5698492c7fa40fc463bf388f05b0b03b74028828b71a79dc89d/SQLAlchemy-2.0.38-cp311-cp311-win_amd64.whl", hash = "sha256:f9d57f1b3061b3e21476b0ad5f0397b112b94ace21d1f439f2db472e568178ae", size = 2102169 },
+    { url = "https://files.pythonhosted.org/packages/5a/f8/6d0424af1442c989b655a7b5f608bc2ae5e4f94cdf6df9f6054f629dc587/SQLAlchemy-2.0.38-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12d5b06a1f3aeccf295a5843c86835033797fea292c60e72b07bcb5d820e6dd3", size = 2104927 },
+    { url = "https://files.pythonhosted.org/packages/25/80/fc06e65fca0a19533e2bfab633a5633ed8b6ee0b9c8d580acf84609ce4da/SQLAlchemy-2.0.38-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e036549ad14f2b414c725349cce0772ea34a7ab008e9cd67f9084e4f371d1f32", size = 2095317 },
+    { url = "https://files.pythonhosted.org/packages/98/2d/5d66605f76b8e344813237dc160a01f03b987201e974b46056a7fb94a874/SQLAlchemy-2.0.38-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee3bee874cb1fadee2ff2b79fc9fc808aa638670f28b2145074538d4a6a5028e", size = 3244735 },
+    { url = "https://files.pythonhosted.org/packages/73/8d/b0539e8dce90861efc38fea3eefb15a5d0cfeacf818614762e77a9f192f9/SQLAlchemy-2.0.38-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e185ea07a99ce8b8edfc788c586c538c4b1351007e614ceb708fd01b095ef33e", size = 3255581 },
+    { url = "https://files.pythonhosted.org/packages/ac/a5/94e1e44bf5bdffd1782807fcc072542b110b950f0be53f49e68b5f5eca1b/SQLAlchemy-2.0.38-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b79ee64d01d05a5476d5cceb3c27b5535e6bb84ee0f872ba60d9a8cd4d0e6579", size = 3190877 },
+    { url = "https://files.pythonhosted.org/packages/91/13/f08b09996dce945aec029c64f61c13b4788541ac588d9288e31e0d3d8850/SQLAlchemy-2.0.38-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:afd776cf1ebfc7f9aa42a09cf19feadb40a26366802d86c1fba080d8e5e74bdd", size = 3217485 },
+    { url = "https://files.pythonhosted.org/packages/13/8f/8cfe2ba5ba6d8090f4de0e658330c53be6b7bf430a8df1b141c2b180dcdf/SQLAlchemy-2.0.38-cp312-cp312-win32.whl", hash = "sha256:a5645cd45f56895cfe3ca3459aed9ff2d3f9aaa29ff7edf557fa7a23515a3725", size = 2075254 },
+    { url = "https://files.pythonhosted.org/packages/c2/5c/e3c77fae41862be1da966ca98eec7fbc07cdd0b00f8b3e1ef2a13eaa6cca/SQLAlchemy-2.0.38-cp312-cp312-win_amd64.whl", hash = "sha256:1052723e6cd95312f6a6eff9a279fd41bbae67633415373fdac3c430eca3425d", size = 2100865 },
+    { url = "https://files.pythonhosted.org/packages/aa/e4/592120713a314621c692211eba034d09becaf6bc8848fabc1dc2a54d8c16/SQLAlchemy-2.0.38-py3-none-any.whl", hash = "sha256:63178c675d4c80def39f1febd625a6333f44c0ba269edd8a468b156394b27753", size = 1896347 },
 ]
 
 [package.optional-dependencies]
@@ -2297,14 +2085,14 @@ mypy = [
 
 [[package]]
 name = "starlette"
-version = "0.41.3"
+version = "0.45.3"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "anyio" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/1a/4c/9b5764bd22eec91c4039ef4c55334e9187085da2d8a2df7bd570869aae18/starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835", size = 2574159 }
+sdist = { url = "https://files.pythonhosted.org/packages/ff/fb/2984a686808b89a6781526129a4b51266f678b2d2b97ab2d325e56116df8/starlette-0.45.3.tar.gz", hash = "sha256:2cbcba2a75806f8a41c722141486f37c28e30a0921c5f6fe4346cb0dcee1302f", size = 2574076 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/96/00/2b325970b3060c7cecebab6d295afe763365822b1306a12eeab198f74323/starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7", size = 73225 },
+    { url = "https://files.pythonhosted.org/packages/d9/61/f2b52e107b1fc8944b33ef56bf6ac4ebbe16d91b94d2b87ce013bf63fb84/starlette-0.45.3-py3-none-any.whl", hash = "sha256:dfb6d332576f136ec740296c7e8bb8c8a7125044e7c6da30744718880cdd059d", size = 71507 },
 ]
 
 [[package]]
@@ -2393,16 +2181,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 },
     { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 },
     { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 },
-    { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 },
-    { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 },
-    { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 },
-    { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 },
-    { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 },
-    { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 },
-    { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 },
-    { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 },
-    { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 },
-    { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 },
     { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 },
 ]
 
@@ -2442,6 +2220,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 },
 ]
 
+[[package]]
+name = "tzdata"
+version = "2025.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/43/0f/fa4723f22942480be4ca9527bbde8d43f6c3f2fe8412f00e7f5f6746bc8b/tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", size = 194950 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/0f/dd/84f10e23edd882c6f968c21c2434fe67bd4a528967067515feca9e611e5e/tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639", size = 346762 },
+]
+
 [[package]]
 name = "uritemplate"
 version = "4.1.1"
@@ -2502,160 +2289,117 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770 },
     { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321 },
     { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022 },
-    { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123 },
-    { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325 },
-    { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806 },
-    { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068 },
-    { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428 },
-    { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018 },
 ]
 
 [[package]]
 name = "virtualenv"
-version = "20.28.1"
+version = "20.29.2"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "distlib" },
     { name = "filelock" },
     { name = "platformdirs" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/50/39/689abee4adc85aad2af8174bb195a819d0be064bf55fcc73b49d2b28ae77/virtualenv-20.28.1.tar.gz", hash = "sha256:5d34ab240fdb5d21549b76f9e8ff3af28252f5499fb6d6f031adac4e5a8c5329", size = 7650532 }
+sdist = { url = "https://files.pythonhosted.org/packages/f1/88/dacc875dd54a8acadb4bcbfd4e3e86df8be75527116c91d8f9784f5e9cab/virtualenv-20.29.2.tar.gz", hash = "sha256:fdaabebf6d03b5ba83ae0a02cfe96f48a716f4fae556461d180825866f75b728", size = 4320272 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/51/8f/dfb257ca6b4e27cb990f1631142361e4712badab8e3ca8dc134d96111515/virtualenv-20.28.1-py3-none-any.whl", hash = "sha256:412773c85d4dab0409b83ec36f7a6499e72eaf08c80e81e9576bca61831c71cb", size = 4276719 },
+    { url = "https://files.pythonhosted.org/packages/93/fa/849483d56773ae29740ae70043ad88e068f98a6401aa819b5d6bee604683/virtualenv-20.29.2-py3-none-any.whl", hash = "sha256:febddfc3d1ea571bdb1dc0f98d7b45d24def7428214d4fb73cc486c9568cce6a", size = 4301478 },
 ]
 
 [[package]]
 name = "watchfiles"
-version = "1.0.3"
+version = "1.0.4"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "anyio" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/3c/7e/4569184ea04b501840771b8fcecee19b2233a8b72c196061263c0ef23c0b/watchfiles-1.0.3.tar.gz", hash = "sha256:f3ff7da165c99a5412fe5dd2304dd2dbaaaa5da718aad942dcb3a178eaa70c56", size = 38185 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/24/a8/06e2d5f840b285718a09be7c71ea19b7177b005cec87b8923dd7e8541b20/watchfiles-1.0.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ffe709b1d0bc2e9921257569675674cafb3a5f8af689ab9f3f2b3f88775b960f", size = 394821 },
-    { url = "https://files.pythonhosted.org/packages/57/9f/f98a57ada3d4b1fcd0e325aa6c307e2248ecb048f71c96fba34a602f02e7/watchfiles-1.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:418c5ce332f74939ff60691e5293e27c206c8164ce2b8ce0d9abf013003fb7fe", size = 384898 },
-    { url = "https://files.pythonhosted.org/packages/a3/31/33ba914010cbfd01033ca3727aff6585b6b2ea2b051b6fbaecdf4e2160b9/watchfiles-1.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f492d2907263d6d0d52f897a68647195bc093dafed14508a8d6817973586b6b", size = 441710 },
-    { url = "https://files.pythonhosted.org/packages/d9/dd/e56b2ef07c2c34e4152950f0ce98a1081215ef027cf39e5dab61a0f8bd95/watchfiles-1.0.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:48c9f3bc90c556a854f4cab6a79c16974099ccfa3e3e150673d82d47a4bc92c9", size = 447681 },
-    { url = "https://files.pythonhosted.org/packages/60/8f/3837df33f3d0cbef8ae59559891d688490bf2960373ea077ff11cbf79115/watchfiles-1.0.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75d3bcfa90454dba8df12adc86b13b6d85fda97d90e708efc036c2760cc6ba44", size = 472312 },
-    { url = "https://files.pythonhosted.org/packages/5a/b3/95d103e5bb609b20f175e8acdf8b32c4b091f96f781c066fd3bff2b17778/watchfiles-1.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5691340f259b8f76b45fb31b98e594d46c36d1dc8285efa7975f7f50230c9093", size = 494779 },
-    { url = "https://files.pythonhosted.org/packages/4f/f0/9fdc60daf5abf7b0deb225c9b0a37fd72dc407fa33f071ae2f70e84e268c/watchfiles-1.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e263cc718545b7f897baeac1f00299ab6fabe3e18caaacacb0edf6d5f35513c", size = 492090 },
-    { url = "https://files.pythonhosted.org/packages/96/e5/a9967e77f173280ab1abbfd7ead90f2b94060574968baf5e6d7cbe9dd490/watchfiles-1.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c6cf7709ed3e55704cc06f6e835bf43c03bc8e3cb8ff946bf69a2e0a78d9d77", size = 443713 },
-    { url = "https://files.pythonhosted.org/packages/60/38/e5390d4633a558878113e45d32e39d30cf58eb94e0359f41737be209321b/watchfiles-1.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:703aa5e50e465be901e0e0f9d5739add15e696d8c26c53bc6fc00eb65d7b9469", size = 615306 },
-    { url = "https://files.pythonhosted.org/packages/5c/27/8a1ee74544c93e3242ca073087b45c64367aeb6897b622e43c8172c2b421/watchfiles-1.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bfcae6aecd9e0cb425f5145afee871465b98b75862e038d42fe91fd753ddd780", size = 614333 },
-    { url = "https://files.pythonhosted.org/packages/fc/f8/25698f5b734907662b50acf3e81996053abdfe26fcf38804d028412876a8/watchfiles-1.0.3-cp311-cp311-win32.whl", hash = "sha256:6a76494d2c5311584f22416c5a87c1e2cb954ff9b5f0988027bc4ef2a8a67181", size = 270987 },
-    { url = "https://files.pythonhosted.org/packages/39/78/f600dee7b387e6088c8d1f4c898a4340d07aecfe6406bd90ec4c1925ef08/watchfiles-1.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:cf745cbfad6389c0e331786e5fe9ae3f06e9d9c2ce2432378e1267954793975c", size = 284098 },
-    { url = "https://files.pythonhosted.org/packages/ca/6f/27ba8aec0a4b45a6063454465eefb42777158081d9df18eab5f1d6a3bd8a/watchfiles-1.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:2dcc3f60c445f8ce14156854a072ceb36b83807ed803d37fdea2a50e898635d6", size = 276804 },
-    { url = "https://files.pythonhosted.org/packages/bf/a9/c8b5ab33444306e1a324cb2b51644f8458dd459e30c3841f925012893e6a/watchfiles-1.0.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:93436ed550e429da007fbafb723e0769f25bae178fbb287a94cb4ccdf42d3af3", size = 391395 },
-    { url = "https://files.pythonhosted.org/packages/ad/d3/403af5f07359863c03951796ddab265ee8cce1a6147510203d0bf43950e7/watchfiles-1.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c18f3502ad0737813c7dad70e3e1cc966cc147fbaeef47a09463bbffe70b0a00", size = 381432 },
-    { url = "https://files.pythonhosted.org/packages/f6/5f/921f2f2beabaf24b1ad81ac22bb69df8dd5771fdb68d6f34a5912a420941/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a5bc3ca468bb58a2ef50441f953e1f77b9a61bd1b8c347c8223403dc9b4ac9a", size = 441448 },
-    { url = "https://files.pythonhosted.org/packages/63/d7/67d0d750b246f248ccdb400a85a253e93e419ea5b6cbe968fa48b97a5f30/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0d1ec043f02ca04bf21b1b32cab155ce90c651aaf5540db8eb8ad7f7e645cba8", size = 446852 },
-    { url = "https://files.pythonhosted.org/packages/53/7c/d7cd94c7d0905f1e2f1c2232ea9bc39b1a48affd007e09c547ead96edb8f/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f58d3bfafecf3d81c15d99fc0ecf4319e80ac712c77cf0ce2661c8cf8bf84066", size = 471662 },
-    { url = "https://files.pythonhosted.org/packages/26/81/738f8e66f7525753996b8aa292f78dcec1ef77887d62e6cdfb04cc2f352f/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1df924ba82ae9e77340101c28d56cbaff2c991bd6fe8444a545d24075abb0a87", size = 493765 },
-    { url = "https://files.pythonhosted.org/packages/d2/50/78e21f5da24ab39114e9b24f7b0945ea1c6fc7bc9ae86cd87f8eaeb47325/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:632a52dcaee44792d0965c17bdfe5dc0edad5b86d6a29e53d6ad4bf92dc0ff49", size = 490558 },
-    { url = "https://files.pythonhosted.org/packages/a8/93/1873fea6354b2858eae8970991d64e9a449d87726d596490d46bf00af8ed/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bf4b459d94a0387617a1b499f314aa04d8a64b7a0747d15d425b8c8b151da0", size = 442808 },
-    { url = "https://files.pythonhosted.org/packages/4f/b4/2fc4c92fb28b029f66d04a4d430fe929284e9ff717b04bb7a3bb8a7a5605/watchfiles-1.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca94c85911601b097d53caeeec30201736ad69a93f30d15672b967558df02885", size = 615287 },
-    { url = "https://files.pythonhosted.org/packages/1e/d4/93da24db39257e440240d338b617c5153ad11d361c34108f5c0e1e0743eb/watchfiles-1.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:65ab1fb635476f6170b07e8e21db0424de94877e4b76b7feabfe11f9a5fc12b5", size = 612812 },
-    { url = "https://files.pythonhosted.org/packages/c6/67/9fd3661c2dc0309abd6021876653d91e8b64fb279529e2cadaa3520ef3e3/watchfiles-1.0.3-cp312-cp312-win32.whl", hash = "sha256:49bc1bc26abf4f32e132652f4b3bfeec77d8f8f62f57652703ef127e85a3e38d", size = 271642 },
-    { url = "https://files.pythonhosted.org/packages/ae/aa/8c887edb78cd67f5d4d6a35c3aeb46d748643ebf962163130fb1871e2ee0/watchfiles-1.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:48681c86f2cb08348631fed788a116c89c787fdf1e6381c5febafd782f6c3b44", size = 285505 },
-    { url = "https://files.pythonhosted.org/packages/7b/31/d212fa6390f0e73a91913ada0b925b294a78d67794795371208baf73f0b5/watchfiles-1.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:9e080cf917b35b20c889225a13f290f2716748362f6071b859b60b8847a6aa43", size = 277263 },
-    { url = "https://files.pythonhosted.org/packages/36/77/0ceb864c854c59bc5326484f88a900c70b4a05e3792e0ce340689988dd5e/watchfiles-1.0.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e153a690b7255c5ced17895394b4f109d5dcc2a4f35cb809374da50f0e5c456a", size = 391061 },
-    { url = "https://files.pythonhosted.org/packages/00/66/327046cfe276a6e4af1a9a58fc99321e25783e501dc68c4c82de2d1bd3a7/watchfiles-1.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ac1be85fe43b4bf9a251978ce5c3bb30e1ada9784290441f5423a28633a958a7", size = 381177 },
-    { url = "https://files.pythonhosted.org/packages/66/8a/420e2833deaa88e8ca7d94a497ec60fde610c66206a1776f049dc5ad3a4e/watchfiles-1.0.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec98e31e1844eac860e70d9247db9d75440fc8f5f679c37d01914568d18721", size = 441293 },
-    { url = "https://files.pythonhosted.org/packages/58/56/2627795ecdf3f0f361458cfa74c583d5041615b9ad81bc25f8c66a6c44a2/watchfiles-1.0.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0179252846be03fa97d4d5f8233d1c620ef004855f0717712ae1c558f1974a16", size = 446209 },
-    { url = "https://files.pythonhosted.org/packages/8f/d0/11c8dcd8a9995f0c075d76f1d06068bbb7a17583a19c5be75361497a4074/watchfiles-1.0.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:995c374e86fa82126c03c5b4630c4e312327ecfe27761accb25b5e1d7ab50ec8", size = 471227 },
-    { url = "https://files.pythonhosted.org/packages/cb/8f/baa06574eaf48173882c4cdc3636993d0854661be7d88193e015ef996c73/watchfiles-1.0.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29b9cb35b7f290db1c31fb2fdf8fc6d3730cfa4bca4b49761083307f441cac5a", size = 493205 },
-    { url = "https://files.pythonhosted.org/packages/ee/e8/9af886b4d3daa281047b542ffd2eb8f76dae9dd6ca0e21c5df4593b98574/watchfiles-1.0.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f8dc09ae69af50bead60783180f656ad96bd33ffbf6e7a6fce900f6d53b08f1", size = 489090 },
-    { url = "https://files.pythonhosted.org/packages/81/02/62085db54b151fc02e22d47b288d19e99031dc9af73151289a7ab6621f9a/watchfiles-1.0.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:489b80812f52a8d8c7b0d10f0d956db0efed25df2821c7a934f6143f76938bd6", size = 442610 },
-    { url = "https://files.pythonhosted.org/packages/61/81/980439c5d3fd3c69ba7124a56e1016d0b824ced2192ffbfe7062d53f524b/watchfiles-1.0.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:228e2247de583475d4cebf6b9af5dc9918abb99d1ef5ee737155bb39fb33f3c0", size = 614781 },
-    { url = "https://files.pythonhosted.org/packages/55/98/e11401d8e9cd5d2bd0e95e9bf750f397489681965ee0c72fb84732257912/watchfiles-1.0.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1550be1a5cb3be08a3fb84636eaafa9b7119b70c71b0bed48726fd1d5aa9b868", size = 612637 },
-    { url = "https://files.pythonhosted.org/packages/50/be/8393b68f2add0f839be6863f151bd6a7b242efc6eb2ce0c9f7d135d529cc/watchfiles-1.0.3-cp313-cp313-win32.whl", hash = "sha256:16db2d7e12f94818cbf16d4c8938e4d8aaecee23826344addfaaa671a1527b07", size = 271170 },
-    { url = "https://files.pythonhosted.org/packages/f0/da/725f97a8b1b4e7b3e4331cce3ef921b12568af3af403b9f0f61ede036898/watchfiles-1.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:160eff7d1267d7b025e983ca8460e8cc67b328284967cbe29c05f3c3163711a3", size = 285246 },
+sdist = { url = "https://files.pythonhosted.org/packages/f5/26/c705fc77d0a9ecdb9b66f1e2976d95b81df3cae518967431e7dbf9b5e219/watchfiles-1.0.4.tar.gz", hash = "sha256:6ba473efd11062d73e4f00c2b730255f9c1bdd73cd5f9fe5b5da8dbd4a717205", size = 94625 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/0f/bb/8461adc4b1fed009546fb797fc0d5698dcfe5e289cb37e1b8f16a93cdc30/watchfiles-1.0.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2a9f93f8439639dc244c4d2902abe35b0279102bca7bbcf119af964f51d53c19", size = 394869 },
+    { url = "https://files.pythonhosted.org/packages/55/88/9ebf36b3547176d1709c320de78c1fa3263a46be31b5b1267571d9102686/watchfiles-1.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9eea33ad8c418847dd296e61eb683cae1c63329b6d854aefcd412e12d94ee235", size = 384905 },
+    { url = "https://files.pythonhosted.org/packages/03/8a/04335ce23ef78d8c69f0913e8b20cf7d9233e3986543aeef95ef2d6e43d2/watchfiles-1.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31f1a379c9dcbb3f09cf6be1b7e83b67c0e9faabed0471556d9438a4a4e14202", size = 449944 },
+    { url = "https://files.pythonhosted.org/packages/17/4e/c8d5dcd14fe637f4633616dabea8a4af0a10142dccf3b43e0f081ba81ab4/watchfiles-1.0.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab594e75644421ae0a2484554832ca5895f8cab5ab62de30a1a57db460ce06c6", size = 456020 },
+    { url = "https://files.pythonhosted.org/packages/5e/74/3e91e09e1861dd7fbb1190ce7bd786700dc0fbc2ccd33bb9fff5de039229/watchfiles-1.0.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc2eb5d14a8e0d5df7b36288979176fbb39672d45184fc4b1c004d7c3ce29317", size = 482983 },
+    { url = "https://files.pythonhosted.org/packages/a1/3d/e64de2d1ce4eb6a574fd78ce3a28c279da263be9ef3cfcab6f708df192f2/watchfiles-1.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f68d8e9d5a321163ddacebe97091000955a1b74cd43724e346056030b0bacee", size = 520320 },
+    { url = "https://files.pythonhosted.org/packages/2c/bd/52235f7063b57240c66a991696ed27e2a18bd6fcec8a1ea5a040b70d0611/watchfiles-1.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9ce064e81fe79faa925ff03b9f4c1a98b0bbb4a1b8c1b015afa93030cb21a49", size = 500988 },
+    { url = "https://files.pythonhosted.org/packages/3a/b0/ff04194141a5fe650c150400dd9e42667916bc0f52426e2e174d779b8a74/watchfiles-1.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b77d5622ac5cc91d21ae9c2b284b5d5c51085a0bdb7b518dba263d0af006132c", size = 452573 },
+    { url = "https://files.pythonhosted.org/packages/3d/9d/966164332c5a178444ae6d165082d4f351bd56afd9c3ec828eecbf190e6a/watchfiles-1.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1941b4e39de9b38b868a69b911df5e89dc43767feeda667b40ae032522b9b5f1", size = 615114 },
+    { url = "https://files.pythonhosted.org/packages/94/df/f569ae4c1877f96ad4086c153a8eee5a19a3b519487bf5c9454a3438c341/watchfiles-1.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4f8c4998506241dedf59613082d1c18b836e26ef2a4caecad0ec41e2a15e4226", size = 613076 },
+    { url = "https://files.pythonhosted.org/packages/15/ae/8ce5f29e65d5fa5790e3c80c289819c55e12be2e1b9f5b6a0e55e169b97d/watchfiles-1.0.4-cp311-cp311-win32.whl", hash = "sha256:4ebbeca9360c830766b9f0df3640b791be569d988f4be6c06d6fae41f187f105", size = 271013 },
+    { url = "https://files.pythonhosted.org/packages/a4/c6/79dc4a7c598a978e5fafa135090aaf7bbb03b8dec7bada437dfbe578e7ed/watchfiles-1.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:05d341c71f3d7098920f8551d4df47f7b57ac5b8dad56558064c3431bdfc0b74", size = 284229 },
+    { url = "https://files.pythonhosted.org/packages/37/3d/928633723211753f3500bfb138434f080363b87a1b08ca188b1ce54d1e05/watchfiles-1.0.4-cp311-cp311-win_arm64.whl", hash = "sha256:32b026a6ab64245b584acf4931fe21842374da82372d5c039cba6bf99ef722f3", size = 276824 },
+    { url = "https://files.pythonhosted.org/packages/5b/1a/8f4d9a1461709756ace48c98f07772bc6d4519b1e48b5fa24a4061216256/watchfiles-1.0.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:229e6ec880eca20e0ba2f7e2249c85bae1999d330161f45c78d160832e026ee2", size = 391345 },
+    { url = "https://files.pythonhosted.org/packages/bc/d2/6750b7b3527b1cdaa33731438432e7238a6c6c40a9924049e4cebfa40805/watchfiles-1.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5717021b199e8353782dce03bd8a8f64438832b84e2885c4a645f9723bf656d9", size = 381515 },
+    { url = "https://files.pythonhosted.org/packages/4e/17/80500e42363deef1e4b4818729ed939aaddc56f82f4e72b2508729dd3c6b/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0799ae68dfa95136dde7c472525700bd48777875a4abb2ee454e3ab18e9fc712", size = 449767 },
+    { url = "https://files.pythonhosted.org/packages/10/37/1427fa4cfa09adbe04b1e97bced19a29a3462cc64c78630787b613a23f18/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43b168bba889886b62edb0397cab5b6490ffb656ee2fcb22dec8bfeb371a9e12", size = 455677 },
+    { url = "https://files.pythonhosted.org/packages/c5/7a/39e9397f3a19cb549a7d380412fd9e507d4854eddc0700bfad10ef6d4dba/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb2c46e275fbb9f0c92e7654b231543c7bbfa1df07cdc4b99fa73bedfde5c844", size = 482219 },
+    { url = "https://files.pythonhosted.org/packages/45/2d/7113931a77e2ea4436cad0c1690c09a40a7f31d366f79c6f0a5bc7a4f6d5/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:857f5fc3aa027ff5e57047da93f96e908a35fe602d24f5e5d8ce64bf1f2fc733", size = 518830 },
+    { url = "https://files.pythonhosted.org/packages/f9/1b/50733b1980fa81ef3c70388a546481ae5fa4c2080040100cd7bf3bf7b321/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55ccfd27c497b228581e2838d4386301227fc0cb47f5a12923ec2fe4f97b95af", size = 497997 },
+    { url = "https://files.pythonhosted.org/packages/2b/b4/9396cc61b948ef18943e7c85ecfa64cf940c88977d882da57147f62b34b1/watchfiles-1.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c11ea22304d17d4385067588123658e9f23159225a27b983f343fcffc3e796a", size = 452249 },
+    { url = "https://files.pythonhosted.org/packages/fb/69/0c65a5a29e057ad0dc691c2fa6c23b2983c7dabaa190ba553b29ac84c3cc/watchfiles-1.0.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:74cb3ca19a740be4caa18f238298b9d472c850f7b2ed89f396c00a4c97e2d9ff", size = 614412 },
+    { url = "https://files.pythonhosted.org/packages/7f/b9/319fcba6eba5fad34327d7ce16a6b163b39741016b1996f4a3c96b8dd0e1/watchfiles-1.0.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c7cce76c138a91e720d1df54014a047e680b652336e1b73b8e3ff3158e05061e", size = 611982 },
+    { url = "https://files.pythonhosted.org/packages/f1/47/143c92418e30cb9348a4387bfa149c8e0e404a7c5b0585d46d2f7031b4b9/watchfiles-1.0.4-cp312-cp312-win32.whl", hash = "sha256:b045c800d55bc7e2cadd47f45a97c7b29f70f08a7c2fa13241905010a5493f94", size = 271822 },
+    { url = "https://files.pythonhosted.org/packages/ea/94/b0165481bff99a64b29e46e07ac2e0df9f7a957ef13bec4ceab8515f44e3/watchfiles-1.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:c2acfa49dd0ad0bf2a9c0bb9a985af02e89345a7189be1efc6baa085e0f72d7c", size = 285441 },
+    { url = "https://files.pythonhosted.org/packages/11/de/09fe56317d582742d7ca8c2ca7b52a85927ebb50678d9b0fa8194658f536/watchfiles-1.0.4-cp312-cp312-win_arm64.whl", hash = "sha256:22bb55a7c9e564e763ea06c7acea24fc5d2ee5dfc5dafc5cfbedfe58505e9f90", size = 277141 },
 ]
 
 [[package]]
 name = "websockets"
-version = "14.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/f4/1b/380b883ce05bb5f45a905b61790319a28958a9ab1e4b6b95ff5464b60ca1/websockets-14.1.tar.gz", hash = "sha256:398b10c77d471c0aab20a845e7a60076b6390bfdaac7a6d2edb0d2c59d75e8d8", size = 162840 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/97/ed/c0d03cb607b7fe1f7ff45e2cd4bb5cd0f9e3299ced79c2c303a6fff44524/websockets-14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:449d77d636f8d9c17952628cc7e3b8faf6e92a17ec581ec0c0256300717e1512", size = 161949 },
-    { url = "https://files.pythonhosted.org/packages/06/91/bf0a44e238660d37a2dda1b4896235d20c29a2d0450f3a46cd688f43b239/websockets-14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a35f704be14768cea9790d921c2c1cc4fc52700410b1c10948511039be824aac", size = 159606 },
-    { url = "https://files.pythonhosted.org/packages/ff/b8/7185212adad274c2b42b6a24e1ee6b916b7809ed611cbebc33b227e5c215/websockets-14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b1f3628a0510bd58968c0f60447e7a692933589b791a6b572fcef374053ca280", size = 159854 },
-    { url = "https://files.pythonhosted.org/packages/5a/8a/0849968d83474be89c183d8ae8dcb7f7ada1a3c24f4d2a0d7333c231a2c3/websockets-14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c3deac3748ec73ef24fc7be0b68220d14d47d6647d2f85b2771cb35ea847aa1", size = 169402 },
-    { url = "https://files.pythonhosted.org/packages/bd/4f/ef886e37245ff6b4a736a09b8468dae05d5d5c99de1357f840d54c6f297d/websockets-14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7048eb4415d46368ef29d32133134c513f507fff7d953c18c91104738a68c3b3", size = 168406 },
-    { url = "https://files.pythonhosted.org/packages/11/43/e2dbd4401a63e409cebddedc1b63b9834de42f51b3c84db885469e9bdcef/websockets-14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cf0ad281c979306a6a34242b371e90e891bce504509fb6bb5246bbbf31e7b6", size = 168776 },
-    { url = "https://files.pythonhosted.org/packages/6d/d6/7063e3f5c1b612e9f70faae20ebaeb2e684ffa36cb959eb0862ee2809b32/websockets-14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cc1fc87428c1d18b643479caa7b15db7d544652e5bf610513d4a3478dbe823d0", size = 169083 },
-    { url = "https://files.pythonhosted.org/packages/49/69/e6f3d953f2fa0f8a723cf18cd011d52733bd7f6e045122b24e0e7f49f9b0/websockets-14.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f95ba34d71e2fa0c5d225bde3b3bdb152e957150100e75c86bc7f3964c450d89", size = 168529 },
-    { url = "https://files.pythonhosted.org/packages/70/ff/f31fa14561fc1d7b8663b0ed719996cf1f581abee32c8fb2f295a472f268/websockets-14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9481a6de29105d73cf4515f2bef8eb71e17ac184c19d0b9918a3701c6c9c4f23", size = 168475 },
-    { url = "https://files.pythonhosted.org/packages/f1/15/b72be0e4bf32ff373aa5baef46a4c7521b8ea93ad8b49ca8c6e8e764c083/websockets-14.1-cp311-cp311-win32.whl", hash = "sha256:368a05465f49c5949e27afd6fbe0a77ce53082185bbb2ac096a3a8afaf4de52e", size = 162833 },
-    { url = "https://files.pythonhosted.org/packages/bc/ef/2d81679acbe7057ffe2308d422f744497b52009ea8bab34b6d74a2657d1d/websockets-14.1-cp311-cp311-win_amd64.whl", hash = "sha256:6d24fc337fc055c9e83414c94e1ee0dee902a486d19d2a7f0929e49d7d604b09", size = 163263 },
-    { url = "https://files.pythonhosted.org/packages/55/64/55698544ce29e877c9188f1aee9093712411a8fc9732cca14985e49a8e9c/websockets-14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed907449fe5e021933e46a3e65d651f641975a768d0649fee59f10c2985529ed", size = 161957 },
-    { url = "https://files.pythonhosted.org/packages/a2/b1/b088f67c2b365f2c86c7b48edb8848ac27e508caf910a9d9d831b2f343cb/websockets-14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:87e31011b5c14a33b29f17eb48932e63e1dcd3fa31d72209848652310d3d1f0d", size = 159620 },
-    { url = "https://files.pythonhosted.org/packages/c1/89/2a09db1bbb40ba967a1b8225b07b7df89fea44f06de9365f17f684d0f7e6/websockets-14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bc6ccf7d54c02ae47a48ddf9414c54d48af9c01076a2e1023e3b486b6e72c707", size = 159852 },
-    { url = "https://files.pythonhosted.org/packages/ca/c1/f983138cd56e7d3079f1966e81f77ce6643f230cd309f73aa156bb181749/websockets-14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9777564c0a72a1d457f0848977a1cbe15cfa75fa2f67ce267441e465717dcf1a", size = 169675 },
-    { url = "https://files.pythonhosted.org/packages/c1/c8/84191455d8660e2a0bdb33878d4ee5dfa4a2cedbcdc88bbd097303b65bfa/websockets-14.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a655bde548ca98f55b43711b0ceefd2a88a71af6350b0c168aa77562104f3f45", size = 168619 },
-    { url = "https://files.pythonhosted.org/packages/8d/a7/62e551fdcd7d44ea74a006dc193aba370505278ad76efd938664531ce9d6/websockets-14.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfff83ca578cada2d19e665e9c8368e1598d4e787422a460ec70e531dbdd58", size = 169042 },
-    { url = "https://files.pythonhosted.org/packages/ad/ed/1532786f55922c1e9c4d329608e36a15fdab186def3ca9eb10d7465bc1cc/websockets-14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6a6c9bcf7cdc0fd41cc7b7944447982e8acfd9f0d560ea6d6845428ed0562058", size = 169345 },
-    { url = "https://files.pythonhosted.org/packages/ea/fb/160f66960d495df3de63d9bcff78e1b42545b2a123cc611950ffe6468016/websockets-14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4b6caec8576e760f2c7dd878ba817653144d5f369200b6ddf9771d64385b84d4", size = 168725 },
-    { url = "https://files.pythonhosted.org/packages/cf/53/1bf0c06618b5ac35f1d7906444b9958f8485682ab0ea40dee7b17a32da1e/websockets-14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eb6d38971c800ff02e4a6afd791bbe3b923a9a57ca9aeab7314c21c84bf9ff05", size = 168712 },
-    { url = "https://files.pythonhosted.org/packages/e5/22/5ec2f39fff75f44aa626f86fa7f20594524a447d9c3be94d8482cd5572ef/websockets-14.1-cp312-cp312-win32.whl", hash = "sha256:1d045cbe1358d76b24d5e20e7b1878efe578d9897a25c24e6006eef788c0fdf0", size = 162838 },
-    { url = "https://files.pythonhosted.org/packages/74/27/28f07df09f2983178db7bf6c9cccc847205d2b92ced986cd79565d68af4f/websockets-14.1-cp312-cp312-win_amd64.whl", hash = "sha256:90f4c7a069c733d95c308380aae314f2cb45bd8a904fb03eb36d1a4983a4993f", size = 163277 },
-    { url = "https://files.pythonhosted.org/packages/34/77/812b3ba5110ed8726eddf9257ab55ce9e85d97d4aa016805fdbecc5e5d48/websockets-14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3630b670d5057cd9e08b9c4dab6493670e8e762a24c2c94ef312783870736ab9", size = 161966 },
-    { url = "https://files.pythonhosted.org/packages/8d/24/4fcb7aa6986ae7d9f6d083d9d53d580af1483c5ec24bdec0978307a0f6ac/websockets-14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36ebd71db3b89e1f7b1a5deaa341a654852c3518ea7a8ddfdf69cc66acc2db1b", size = 159625 },
-    { url = "https://files.pythonhosted.org/packages/f8/47/2a0a3a2fc4965ff5b9ce9324d63220156bd8bedf7f90824ab92a822e65fd/websockets-14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5b918d288958dc3fa1c5a0b9aa3256cb2b2b84c54407f4813c45d52267600cd3", size = 159857 },
-    { url = "https://files.pythonhosted.org/packages/dd/c8/d7b425011a15e35e17757e4df75b25e1d0df64c0c315a44550454eaf88fc/websockets-14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00fe5da3f037041da1ee0cf8e308374e236883f9842c7c465aa65098b1c9af59", size = 169635 },
-    { url = "https://files.pythonhosted.org/packages/93/39/6e3b5cffa11036c40bd2f13aba2e8e691ab2e01595532c46437b56575678/websockets-14.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8149a0f5a72ca36720981418eeffeb5c2729ea55fa179091c81a0910a114a5d2", size = 168578 },
-    { url = "https://files.pythonhosted.org/packages/cf/03/8faa5c9576299b2adf34dcccf278fc6bbbcda8a3efcc4d817369026be421/websockets-14.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77569d19a13015e840b81550922056acabc25e3f52782625bc6843cfa034e1da", size = 169018 },
-    { url = "https://files.pythonhosted.org/packages/8c/05/ea1fec05cc3a60defcdf0bb9f760c3c6bd2dd2710eff7ac7f891864a22ba/websockets-14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cf5201a04550136ef870aa60ad3d29d2a59e452a7f96b94193bee6d73b8ad9a9", size = 169383 },
-    { url = "https://files.pythonhosted.org/packages/21/1d/eac1d9ed787f80754e51228e78855f879ede1172c8b6185aca8cef494911/websockets-14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:88cf9163ef674b5be5736a584c999e98daf3aabac6e536e43286eb74c126b9c7", size = 168773 },
-    { url = "https://files.pythonhosted.org/packages/0e/1b/e808685530185915299740d82b3a4af3f2b44e56ccf4389397c7a5d95d39/websockets-14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:836bef7ae338a072e9d1863502026f01b14027250a4545672673057997d5c05a", size = 168757 },
-    { url = "https://files.pythonhosted.org/packages/b6/19/6ab716d02a3b068fbbeb6face8a7423156e12c446975312f1c7c0f4badab/websockets-14.1-cp313-cp313-win32.whl", hash = "sha256:0d4290d559d68288da9f444089fd82490c8d2744309113fc26e2da6e48b65da6", size = 162834 },
-    { url = "https://files.pythonhosted.org/packages/6c/fd/ab6b7676ba712f2fc89d1347a4b5bdc6aa130de10404071f2b2606450209/websockets-14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8621a07991add373c3c5c2cf89e1d277e49dc82ed72c75e3afc74bd0acc446f0", size = 163277 },
-    { url = "https://files.pythonhosted.org/packages/b0/0b/c7e5d11020242984d9d37990310520ed663b942333b83a033c2f20191113/websockets-14.1-py3-none-any.whl", hash = "sha256:4d4fc827a20abe6d544a119896f6b78ee13fe81cbfef416f3f2ddf09a03f0e2e", size = 156277 },
+version = "15.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/2e/7a/8bc4d15af7ff30f7ba34f9a172063bfcee9f5001d7cef04bee800a658f33/websockets-15.0.tar.gz", hash = "sha256:ca36151289a15b39d8d683fd8b7abbe26fc50be311066c5f8dcf3cb8cee107ab", size = 175574 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/ee/16/81a7403c8c0a33383de647e89c07824ea6a654e3877d6ff402cbae298cb8/websockets-15.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dd24c4d256558429aeeb8d6c24ebad4e982ac52c50bc3670ae8646c181263965", size = 174702 },
+    { url = "https://files.pythonhosted.org/packages/ef/40/4629202386a3bf1195db9fe41baeb1d6dfd8d72e651d9592d81dae7fdc7c/websockets-15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f83eca8cbfd168e424dfa3b3b5c955d6c281e8fc09feb9d870886ff8d03683c7", size = 172359 },
+    { url = "https://files.pythonhosted.org/packages/7b/33/dfb650e822bc7912d8c542c452497867af91dec81e7b5bf96aca5b419d58/websockets-15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4095a1f2093002c2208becf6f9a178b336b7572512ee0a1179731acb7788e8ad", size = 172604 },
+    { url = "https://files.pythonhosted.org/packages/2e/52/666743114513fcffd43ee5df261a1eb5d41f8e9861b7a190b730732c19ba/websockets-15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb915101dfbf318486364ce85662bb7b020840f68138014972c08331458d41f3", size = 182145 },
+    { url = "https://files.pythonhosted.org/packages/9c/63/5273f146b13aa4a057a95ab0855d9990f3a1ced63693f4365135d1abfacc/websockets-15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:45d464622314973d78f364689d5dbb9144e559f93dca11b11af3f2480b5034e1", size = 181152 },
+    { url = "https://files.pythonhosted.org/packages/0f/ae/075697f3f97de7c26b73ae96d952e13fa36393e0db3f028540b28954e0a9/websockets-15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace960769d60037ca9625b4c578a6f28a14301bd2a1ff13bb00e824ac9f73e55", size = 181523 },
+    { url = "https://files.pythonhosted.org/packages/25/87/06d091bbcbe01903bed3dad3bb4a1a3c516f61e611ec31fffb28abe4974b/websockets-15.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c7cd4b1015d2f60dfe539ee6c95bc968d5d5fad92ab01bb5501a77393da4f596", size = 181791 },
+    { url = "https://files.pythonhosted.org/packages/77/08/5063b6cc1b2aa1fba2ee3b578b777db22fde7145f121d07fd878811e983b/websockets-15.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4f7290295794b5dec470867c7baa4a14182b9732603fd0caf2a5bf1dc3ccabf3", size = 181231 },
+    { url = "https://files.pythonhosted.org/packages/86/ff/af23084df0a7405bb2add12add8c17d6192a8de9480f1b90d12352ba2b7d/websockets-15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3abd670ca7ce230d5a624fd3d55e055215d8d9b723adee0a348352f5d8d12ff4", size = 181191 },
+    { url = "https://files.pythonhosted.org/packages/21/ce/b2bdfcf49201dee0b899edc6a814755763ec03d74f2714923d38453a9e8d/websockets-15.0-cp311-cp311-win32.whl", hash = "sha256:110a847085246ab8d4d119632145224d6b49e406c64f1bbeed45c6f05097b680", size = 175666 },
+    { url = "https://files.pythonhosted.org/packages/8d/7b/444edcd5365538c226b631897975a65bbf5ccf27c77102e17d8f12a306ea/websockets-15.0-cp311-cp311-win_amd64.whl", hash = "sha256:8d7bbbe2cd6ed80aceef2a14e9f1c1b61683194c216472ed5ff33b700e784e37", size = 176105 },
+    { url = "https://files.pythonhosted.org/packages/22/1e/92c4547d7b2a93f848aedaf37e9054111bc00dc11bff4385ca3f80dbb412/websockets-15.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cccc18077acd34c8072578394ec79563664b1c205f7a86a62e94fafc7b59001f", size = 174709 },
+    { url = "https://files.pythonhosted.org/packages/9f/37/eae4830a28061ba552516d84478686b637cd9e57d6a90b45ad69e89cb0af/websockets-15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d4c22992e24f12de340ca5f824121a5b3e1a37ad4360b4e1aaf15e9d1c42582d", size = 172372 },
+    { url = "https://files.pythonhosted.org/packages/46/2f/b409f8b8aa9328d5a47f7a301a43319d540d70cf036d1e6443675978a988/websockets-15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1206432cc6c644f6fc03374b264c5ff805d980311563202ed7fef91a38906276", size = 172607 },
+    { url = "https://files.pythonhosted.org/packages/d6/81/d7e2e4542d4b4df849b0110df1b1f94f2647b71ab4b65d672090931ad2bb/websockets-15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d3cc75ef3e17490042c47e0523aee1bcc4eacd2482796107fd59dd1100a44bc", size = 182422 },
+    { url = "https://files.pythonhosted.org/packages/b6/91/3b303160938d123eea97f58be363f7dbec76e8c59d587e07b5bc257dd584/websockets-15.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b89504227a5311610e4be16071465885a0a3d6b0e82e305ef46d9b064ce5fb72", size = 181362 },
+    { url = "https://files.pythonhosted.org/packages/f2/8b/df6807f1ca339c567aba9a7ab03bfdb9a833f625e8d2b4fc7529e4c701de/websockets-15.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56e3efe356416bc67a8e093607315951d76910f03d2b3ad49c4ade9207bf710d", size = 181787 },
+    { url = "https://files.pythonhosted.org/packages/21/37/e6d3d5ebb0ebcaf98ae84904205c9dcaf3e0fe93e65000b9f08631ed7309/websockets-15.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0f2205cdb444a42a7919690238fb5979a05439b9dbb73dd47c863d39640d85ab", size = 182058 },
+    { url = "https://files.pythonhosted.org/packages/c9/df/6aca296f2be4c638ad20908bb3d7c94ce7afc8d9b4b2b0780d1fc59b359c/websockets-15.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:aea01f40995fa0945c020228ab919b8dfc93fc8a9f2d3d705ab5b793f32d9e99", size = 181434 },
+    { url = "https://files.pythonhosted.org/packages/88/f1/75717a982bab39bbe63c83f9df0e7753e5c98bab907eb4fb5d97fe5c8c11/websockets-15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9f8e33747b1332db11cf7fcf4a9512bef9748cb5eb4d3f7fbc8c30d75dc6ffc", size = 181431 },
+    { url = "https://files.pythonhosted.org/packages/e7/15/cee9e63ed9ac5bfc1a3ae8fc6c02c41745023c21eed622eef142d8fdd749/websockets-15.0-cp312-cp312-win32.whl", hash = "sha256:32e02a2d83f4954aa8c17e03fe8ec6962432c39aca4be7e8ee346b05a3476904", size = 175678 },
+    { url = "https://files.pythonhosted.org/packages/4e/00/993974c60f40faabb725d4dbae8b072ef73b4c4454bd261d3b1d34ace41f/websockets-15.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffc02b159b65c05f2ed9ec176b715b66918a674bd4daed48a9a7a590dd4be1aa", size = 176119 },
+    { url = "https://files.pythonhosted.org/packages/e8/b2/31eec524b53f01cd8343f10a8e429730c52c1849941d1f530f8253b6d934/websockets-15.0-py3-none-any.whl", hash = "sha256:51ffd53c53c4442415b613497a34ba0aa7b99ac07f1e4a62db5dcd640ae6c3c3", size = 169023 },
 ]
 
 [[package]]
 name = "wrapt"
-version = "1.17.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/24/a1/fc03dca9b0432725c2e8cdbf91a349d2194cf03d8523c124faebe581de09/wrapt-1.17.0.tar.gz", hash = "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801", size = 55542 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/0e/40/def56538acddc2f764c157d565b9f989072a1d2f2a8e384324e2e104fc7d/wrapt-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a", size = 38766 },
-    { url = "https://files.pythonhosted.org/packages/89/e2/8c299f384ae4364193724e2adad99f9504599d02a73ec9199bf3f406549d/wrapt-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed", size = 83730 },
-    { url = "https://files.pythonhosted.org/packages/29/ef/fcdb776b12df5ea7180d065b28fa6bb27ac785dddcd7202a0b6962bbdb47/wrapt-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489", size = 75470 },
-    { url = "https://files.pythonhosted.org/packages/55/b5/698bd0bf9fbb3ddb3a2feefbb7ad0dea1205f5d7d05b9cbab54f5db731aa/wrapt-1.17.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9", size = 83168 },
-    { url = "https://files.pythonhosted.org/packages/ce/07/701a5cee28cb4d5df030d4b2649319e36f3d9fdd8000ef1d84eb06b9860d/wrapt-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339", size = 82307 },
-    { url = "https://files.pythonhosted.org/packages/42/92/c48ba92cda6f74cb914dc3c5bba9650dc80b790e121c4b987f3a46b028f5/wrapt-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d", size = 75101 },
-    { url = "https://files.pythonhosted.org/packages/8a/0a/9276d3269334138b88a2947efaaf6335f61d547698e50dff672ade24f2c6/wrapt-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b", size = 81835 },
-    { url = "https://files.pythonhosted.org/packages/b9/4c/39595e692753ef656ea94b51382cc9aea662fef59d7910128f5906486f0e/wrapt-1.17.0-cp311-cp311-win32.whl", hash = "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346", size = 36412 },
-    { url = "https://files.pythonhosted.org/packages/63/bb/c293a67fb765a2ada48f48cd0f2bb957da8161439da4c03ea123b9894c02/wrapt-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a", size = 38744 },
-    { url = "https://files.pythonhosted.org/packages/85/82/518605474beafff11f1a34759f6410ab429abff9f7881858a447e0d20712/wrapt-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569", size = 38904 },
-    { url = "https://files.pythonhosted.org/packages/80/6c/17c3b2fed28edfd96d8417c865ef0b4c955dc52c4e375d86f459f14340f1/wrapt-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504", size = 88622 },
-    { url = "https://files.pythonhosted.org/packages/4a/11/60ecdf3b0fd3dca18978d89acb5d095a05f23299216e925fcd2717c81d93/wrapt-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451", size = 80920 },
-    { url = "https://files.pythonhosted.org/packages/d2/50/dbef1a651578a3520d4534c1e434989e3620380c1ad97e309576b47f0ada/wrapt-1.17.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1", size = 89170 },
-    { url = "https://files.pythonhosted.org/packages/44/a2/78c5956bf39955288c9e0dd62e807b308c3aa15a0f611fbff52aa8d6b5ea/wrapt-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106", size = 86748 },
-    { url = "https://files.pythonhosted.org/packages/99/49/2ee413c78fc0bdfebe5bee590bf3becdc1fab0096a7a9c3b5c9666b2415f/wrapt-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada", size = 79734 },
-    { url = "https://files.pythonhosted.org/packages/c0/8c/4221b7b270e36be90f0930fe15a4755a6ea24093f90b510166e9ed7861ea/wrapt-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4", size = 87552 },
-    { url = "https://files.pythonhosted.org/packages/4c/6b/1aaccf3efe58eb95e10ce8e77c8909b7a6b0da93449a92c4e6d6d10b3a3d/wrapt-1.17.0-cp312-cp312-win32.whl", hash = "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635", size = 36647 },
-    { url = "https://files.pythonhosted.org/packages/b3/4f/243f88ac49df005b9129194c6511b3642818b3e6271ddea47a15e2ee4934/wrapt-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7", size = 38830 },
-    { url = "https://files.pythonhosted.org/packages/67/9c/38294e1bb92b055222d1b8b6591604ca4468b77b1250f59c15256437644f/wrapt-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181", size = 38904 },
-    { url = "https://files.pythonhosted.org/packages/78/b6/76597fb362cbf8913a481d41b14b049a8813cd402a5d2f84e57957c813ae/wrapt-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393", size = 88608 },
-    { url = "https://files.pythonhosted.org/packages/bc/69/b500884e45b3881926b5f69188dc542fb5880019d15c8a0df1ab1dfda1f7/wrapt-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4", size = 80879 },
-    { url = "https://files.pythonhosted.org/packages/52/31/f4cc58afe29eab8a50ac5969963010c8b60987e719c478a5024bce39bc42/wrapt-1.17.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b", size = 89119 },
-    { url = "https://files.pythonhosted.org/packages/aa/9c/05ab6bf75dbae7a9d34975fb6ee577e086c1c26cde3b6cf6051726d33c7c/wrapt-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721", size = 86778 },
-    { url = "https://files.pythonhosted.org/packages/0e/6c/4b8d42e3db355603d35fe5c9db79c28f2472a6fd1ccf4dc25ae46739672a/wrapt-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90", size = 79793 },
-    { url = "https://files.pythonhosted.org/packages/69/23/90e3a2ee210c0843b2c2a49b3b97ffcf9cad1387cb18cbeef9218631ed5a/wrapt-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a", size = 87606 },
-    { url = "https://files.pythonhosted.org/packages/5f/06/3683126491ca787d8d71d8d340e775d40767c5efedb35039d987203393b7/wrapt-1.17.0-cp313-cp313-win32.whl", hash = "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045", size = 36651 },
-    { url = "https://files.pythonhosted.org/packages/f1/bc/3bf6d2ca0d2c030d324ef9272bea0a8fdaff68f3d1fa7be7a61da88e51f7/wrapt-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838", size = 38835 },
-    { url = "https://files.pythonhosted.org/packages/ce/b5/251165c232d87197a81cd362eeb5104d661a2dd3aa1f0b33e4bf61dda8b8/wrapt-1.17.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b", size = 40146 },
-    { url = "https://files.pythonhosted.org/packages/89/33/1e1bdd3e866eeb73d8c4755db1ceb8a80d5bd51ee4648b3f2247adec4e67/wrapt-1.17.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379", size = 113444 },
-    { url = "https://files.pythonhosted.org/packages/9f/7c/94f53b065a43f5dc1fbdd8b80fd8f41284315b543805c956619c0b8d92f0/wrapt-1.17.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d", size = 101246 },
-    { url = "https://files.pythonhosted.org/packages/62/5d/640360baac6ea6018ed5e34e6e80e33cfbae2aefde24f117587cd5efd4b7/wrapt-1.17.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f", size = 109320 },
-    { url = "https://files.pythonhosted.org/packages/e3/cf/6c7a00ae86a2e9482c91170aefe93f4ccda06c1ac86c4de637c69133da59/wrapt-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c", size = 110193 },
-    { url = "https://files.pythonhosted.org/packages/cd/cc/aa718df0d20287e8f953ce0e2f70c0af0fba1d3c367db7ee8bdc46ea7003/wrapt-1.17.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b", size = 100460 },
-    { url = "https://files.pythonhosted.org/packages/f7/16/9f3ac99fe1f6caaa789d67b4e3c562898b532c250769f5255fa8b8b93983/wrapt-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab", size = 106347 },
-    { url = "https://files.pythonhosted.org/packages/64/85/c77a331b2c06af49a687f8b926fc2d111047a51e6f0b0a4baa01ff3a673a/wrapt-1.17.0-cp313-cp313t-win32.whl", hash = "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf", size = 37971 },
-    { url = "https://files.pythonhosted.org/packages/05/9b/b2469f8be9efed24283fd7b9eeb8e913e9bc0715cf919ea8645e428ab7af/wrapt-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a", size = 40755 },
-    { url = "https://files.pythonhosted.org/packages/4b/d9/a8ba5e9507a9af1917285d118388c5eb7a81834873f45df213a6fe923774/wrapt-1.17.0-py3-none-any.whl", hash = "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371", size = 23592 },
+version = "1.17.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/c3/fc/e91cc220803d7bc4db93fb02facd8461c37364151b8494762cc88b0fbcef/wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3", size = 55531 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/cd/f7/a2aab2cbc7a665efab072344a8949a71081eed1d2f451f7f7d2b966594a2/wrapt-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58", size = 53308 },
+    { url = "https://files.pythonhosted.org/packages/50/ff/149aba8365fdacef52b31a258c4dc1c57c79759c335eff0b3316a2664a64/wrapt-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda", size = 38488 },
+    { url = "https://files.pythonhosted.org/packages/65/46/5a917ce85b5c3b490d35c02bf71aedaa9f2f63f2d15d9949cc4ba56e8ba9/wrapt-1.17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438", size = 38776 },
+    { url = "https://files.pythonhosted.org/packages/ca/74/336c918d2915a4943501c77566db41d1bd6e9f4dbc317f356b9a244dfe83/wrapt-1.17.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a", size = 83776 },
+    { url = "https://files.pythonhosted.org/packages/09/99/c0c844a5ccde0fe5761d4305485297f91d67cf2a1a824c5f282e661ec7ff/wrapt-1.17.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000", size = 75420 },
+    { url = "https://files.pythonhosted.org/packages/b4/b0/9fc566b0fe08b282c850063591a756057c3247b2362b9286429ec5bf1721/wrapt-1.17.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6", size = 83199 },
+    { url = "https://files.pythonhosted.org/packages/9d/4b/71996e62d543b0a0bd95dda485219856def3347e3e9380cc0d6cf10cfb2f/wrapt-1.17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b", size = 82307 },
+    { url = "https://files.pythonhosted.org/packages/39/35/0282c0d8789c0dc9bcc738911776c762a701f95cfe113fb8f0b40e45c2b9/wrapt-1.17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662", size = 75025 },
+    { url = "https://files.pythonhosted.org/packages/4f/6d/90c9fd2c3c6fee181feecb620d95105370198b6b98a0770cba090441a828/wrapt-1.17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72", size = 81879 },
+    { url = "https://files.pythonhosted.org/packages/8f/fa/9fb6e594f2ce03ef03eddbdb5f4f90acb1452221a5351116c7c4708ac865/wrapt-1.17.2-cp311-cp311-win32.whl", hash = "sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317", size = 36419 },
+    { url = "https://files.pythonhosted.org/packages/47/f8/fb1773491a253cbc123c5d5dc15c86041f746ed30416535f2a8df1f4a392/wrapt-1.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3", size = 38773 },
+    { url = "https://files.pythonhosted.org/packages/a1/bd/ab55f849fd1f9a58ed7ea47f5559ff09741b25f00c191231f9f059c83949/wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925", size = 53799 },
+    { url = "https://files.pythonhosted.org/packages/53/18/75ddc64c3f63988f5a1d7e10fb204ffe5762bc663f8023f18ecaf31a332e/wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392", size = 38821 },
+    { url = "https://files.pythonhosted.org/packages/48/2a/97928387d6ed1c1ebbfd4efc4133a0633546bec8481a2dd5ec961313a1c7/wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40", size = 38919 },
+    { url = "https://files.pythonhosted.org/packages/73/54/3bfe5a1febbbccb7a2f77de47b989c0b85ed3a6a41614b104204a788c20e/wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d", size = 88721 },
+    { url = "https://files.pythonhosted.org/packages/25/cb/7262bc1b0300b4b64af50c2720ef958c2c1917525238d661c3e9a2b71b7b/wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b", size = 80899 },
+    { url = "https://files.pythonhosted.org/packages/2a/5a/04cde32b07a7431d4ed0553a76fdb7a61270e78c5fd5a603e190ac389f14/wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98", size = 89222 },
+    { url = "https://files.pythonhosted.org/packages/09/28/2e45a4f4771fcfb109e244d5dbe54259e970362a311b67a965555ba65026/wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82", size = 86707 },
+    { url = "https://files.pythonhosted.org/packages/c6/d2/dcb56bf5f32fcd4bd9aacc77b50a539abdd5b6536872413fd3f428b21bed/wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae", size = 79685 },
+    { url = "https://files.pythonhosted.org/packages/80/4e/eb8b353e36711347893f502ce91c770b0b0929f8f0bed2670a6856e667a9/wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9", size = 87567 },
+    { url = "https://files.pythonhosted.org/packages/17/27/4fe749a54e7fae6e7146f1c7d914d28ef599dacd4416566c055564080fe2/wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9", size = 36672 },
+    { url = "https://files.pythonhosted.org/packages/15/06/1dbf478ea45c03e78a6a8c4be4fdc3c3bddea5c8de8a93bc971415e47f0f/wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991", size = 38865 },
+    { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594 },
 ]