diff --git a/.flake8 b/.flake8
deleted file mode 100644
index 01ee522..0000000
--- a/.flake8
+++ /dev/null
@@ -1,7 +0,0 @@
-[flake8]
-max-line-length = 79
-# E203: whitespace before :, flake8 disagrees with PEP-8
-# W503: line break after binary operator, flake8 disagrees with PEP-8
-ignore = E203, W503
-exclude =
- docs/conf.py
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 7192f07..39eae4b 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -1,5 +1,12 @@
name: CI
+env:
+ # Current supported Python version. For applications, there is generally no
+ # reason to support multiple Python versions, so all actions are run with
+ # this version. Quote the version to avoid interpretation as a floating
+ # point number.
+ PYTHON_VERSION: "3.12"
+
"on":
merge_group: {}
pull_request: {}
@@ -23,33 +30,29 @@ jobs:
timeout-minutes: 5
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
- python-version: "3.12"
+ python-version: ${{ env.PYTHON_VERSION }}
- name: Run pre-commit
- uses: pre-commit/action@v3.0.0
+ uses: pre-commit/action@v3.0.1
test:
runs-on: ubuntu-latest
timeout-minutes: 10
- strategy:
- matrix:
- python:
- - "3.12"
-
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Run tox
uses: lsst-sqre/run-tox@v1
with:
- python-version: ${{ matrix.python }}
+ python-version: ${{ env.PYTHON_VERSION }}
tox-envs: "py,coverage-report,typing"
+ tox-requirements: requirements/tox.txt
build:
runs-on: ubuntu-latest
@@ -67,7 +70,7 @@ jobs:
|| startsWith(github.head_ref, 'tickets/'))
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
diff --git a/.github/workflows/dependencies.yaml b/.github/workflows/dependencies.yaml
deleted file mode 100644
index f410005..0000000
--- a/.github/workflows/dependencies.yaml
+++ /dev/null
@@ -1,33 +0,0 @@
-name: Dependency Update
-
-"on":
- schedule:
- - cron: "0 12 * * 1"
- workflow_dispatch: {}
-
-jobs:
- update:
- runs-on: ubuntu-latest
- timeout-minutes: 10
-
- steps:
- - uses: actions/checkout@v3
-
- - name: Run neophile
- uses: lsst-sqre/run-neophile@v1
- with:
- python-version: "3.12"
- mode: pr
- types: pre-commit
- app-id: ${{ secrets.NEOPHILE_APP_ID }}
- app-secret: ${{ secrets.NEOPHILE_PRIVATE_KEY }}
-
- - name: Report status
- if: always()
- uses: ravsamhq/notify-slack-action@v2
- with:
- status: ${{ job.status }}
- notify_when: "failure"
- notification_title: "Periodic dependency update for {repo} failed"
- env:
- SLACK_WEBHOOK_URL: ${{ secrets.SLACK_ALERT_WEBHOOK }}
diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
index e859c26..5cf117d 100644
--- a/.github/workflows/docs.yaml
+++ b/.github/workflows/docs.yaml
@@ -1,5 +1,12 @@
name: Docs
+env:
+ # Current supported Python version. For applications, there is generally no
+ # reason to support multiple Python versions, so all actions are run with
+ # this version. Quote the version to avoid interpretation as a floating
+ # point number.
+ PYTHON_VERSION: "3.12"
+
"on":
push:
branches:
@@ -18,12 +25,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
- python-version: "3.12"
+ python-version: ${{ env.PYTHON_VERSION }}
- name: Install graphviz and ImageMagick
run: sudo apt-get install graphviz imagemagick
@@ -31,8 +38,9 @@ jobs:
- name: Run tox
uses: lsst-sqre/run-tox@v1
with:
- python-version: "3.12"
+ python-version: ${{ env.PYTHON_VERSION }}
tox-envs: "docs"
+ tox-requirements: requirements/tox.txt
- name: Upload documentation
uses: lsst-sqre/ltd-upload@v1
diff --git a/.github/workflows/periodic-ci.yaml b/.github/workflows/periodic-ci.yaml
index 0db9dab..65dd8b4 100644
--- a/.github/workflows/periodic-ci.yaml
+++ b/.github/workflows/periodic-ci.yaml
@@ -5,6 +5,13 @@
name: Periodic CI
+env:
+ # Current supported Python version. For applications, there is generally no
+ # reason to support multiple Python versions, so all actions are run with
+ # this version. Quote the version to avoid interpretation as a floating
+ # point number.
+ PYTHON_VERSION: "3.12"
+
"on":
schedule:
- cron: "0 12 * * 1"
@@ -15,32 +22,32 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
- strategy:
- matrix:
- python:
- - "3.12"
-
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- # Use the oldest supported version of Python to update dependencies,
- # not the matrixed Python version, since this accurately reflects
- # how dependencies should later be updated.
- - name: Run neophile
- uses: lsst-sqre/run-neophile@v1
+ - name: Set up Python
+ uses: actions/setup-python@v5
with:
- python-version: "3.12"
- mode: update
+ python-version: ${{ env.PYTHON_VERSION }}
+
+ - name: Update dependencies
+ run: |
+ pip install --upgrade uv
+ uv venv
+ source .venv/bin/activate
+ make update-deps
+ shell: bash
- name: Run tests in tox
uses: lsst-sqre/run-tox@v1
with:
- python-version: ${{ matrix.python }}
+ python-version: ${{ env.PYTHON_VERSION }}
tox-envs: "lint,typing,py"
+ tox-requirements: requirements/tox.txt
use-cache: false
- name: Report status
- if: always()
+ if: failure()
uses: ravsamhq/notify-slack-action@v2
with:
status: ${{ job.status }}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 03889da..7d2a4c7 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,23 +1,14 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.5.0
+ rev: v5.0.0
hooks:
- id: check-yaml
- id: check-toml
+ - id: trailing-whitespace
- - repo: https://github.com/pycqa/isort
- rev: 5.13.2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.7.2
hooks:
- - id: isort
- additional_dependencies:
- - toml
-
- - repo: https://github.com/psf/black
- rev: 24.1.1
- hooks:
- - id: black
-
- - repo: https://github.com/pycqa/flake8
- rev: 7.0.0
- hooks:
- - id: flake8
+ - id: ruff
+ args: [--fix, --exit-non-zero-on-fix]
+ - id: ruff-format
diff --git a/CHANGELOG.md b/CHANGELOG.md
index be30307..524612a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,24 +2,100 @@
-
-## 0.8.0 (2024-01-04)
+
+
+## 0.13.0 (2024-09-12)
+
+### New features
+
+- Notebook execution jobs can now set _timeouts_. In requests, set a timeout in the `timeout` request field. This can be a number of seconds, or a [human-readable duration string](https://safir.lsst.io/user-guide/datetime.html#parsing-time-intervals) (e.g. "1h30m"). The specified timeout is also repeated in the response body. This timeout applies to the notebook execution, not any time in the queue.
+
+- Errors that prevented a notebook from being executed are now reported in the notebook job response body in the `error` field. The field is an object with a `code` field and a `message` field. The `code` field is a string that can be used to identify the error. Currently the codes are `timeout`, `jupyter_error`, and `unknown`. Note that exceptions raised in the Jupyter notebook aren't considered errors, but are instead reported in the `ipynb_error` field.
+
+
+
+## 0.12.1 (2024-08-02)
+
+### Bug fixes
+
+- When logging into JupyterHub, a Noteburst now looks for XRSF tokens from each redirect.
+
+### Other changes
+
+- Adopt `ruff-shared.toml` from https://github.com/lsst/templates
+- Adopt uv for dependency management and resolution.
+- Adopt explicit ASGITransport for setting up test HTTPX client.
-### Backwards-incompatible changes
+
--
+## 0.12.0 (2024-05-15)
### New features
-- The response to `GET /notebooks/:job_id` now includes an `ipynb_error` field that contains structured information about any exception that occurred when executing the notebook. As well, if an exception occurred, the resultant notebook is still included in the response. That is, notebook failures are no longer considered failed jobs.
+- Create Gafaelfawr service tokens instead of user tokens for authenticated calls to JupyterHub and JupyterLab. Gafaelfawr is standardizing on the new service token type for all service-to-service authentication.
-- The `job_id` is now included in log messages when running the `nbexec` job under arq.
+- Reduced the frequency of keep alive tasks for the Noteburst workers to once every 15 minutes, from once every 5 minutes. This is intended to clean up the logging output.
-- The user guide includes a new tutorial for using the Noteburst web API.
+### Bug fixes
+
+- Correctly extract cookies from the middle of the redirect chain caused by initial authentication to a Nublado lab. This fixes failures seen with labs containing JupyterHub 4.1.3.
+
+
+
+## 0.11.0 (2024-04-24)
+
+### New features
+
+- Add support for `gid` as well as `uid` fields in the worker identity configuration. Both `uid` and `gid` are now validated as integers
+
+
+
+## 0.10.0 (2024-03-26)
+
+### New features
+
+- Add a `NOTEBURST_WORKER_MAX_CONCURRENT_JOBS` environment variable configuration to limit the number of concurrent jobs a worker can run. The default is 3. Previously this was 10. This should be set to be equal or less than the number of CPUs available to the JupyterLab pod.
+
+- The notebook execution client now waits as long as possible for the `/execution` endpoint in the JupyterLab pod to return the executed notebook. Previously the client would wait for a fixed amount of time, which could be too short for long-running notebooks. The JupyterLab server may still time-out the request, though.
+
+### Bug fixes
+
+- Improved handling of the XSRF token when authenticated to JupyterHub and JupyterLab pods. This is required in JupyterLab 4.1.
+
+
+
+## 0.9.1 (2024-03-21)
### Bug fixes
--
+- Fix Slack error messaging in the `nbexec` worker function.
+- Extract and use the actual XSRF token when communicating with the Hub and Lab.
+
+
+
+## 0.9.0 (2024-03-13)
+
+### New features
+
+- Add formatted errors when a job is not found for the `GET /v1/notebooks/:job_id` endpoint.
+
+- Errors and uncaught exceptions are now sent to Slack via a Slack webhook. The webhook URL is set via the `SLACK_WEBHOOK_URL` environment variable.
+
+### Other changes
+
+- The code base now uses Ruff for linting and formatting, replacing black, isort, and flake8. This change is part of the ongoing effort to standardize SQuaRE code bases and improve the developer experience.
+
+
+
+## 0.8.0 (2024-01-04)
+
+### New features
+
+- The response to `GET /notebooks/:job_id` now includes an `ipynb_error` field that contains structured information about any exception that occurred when executing the notebook. As well, if an exception occurred, the resultant notebook is still included in the response. That is, notebook failures are no longer considered failed jobs.
+
+- The `job_id` is now included in log messages when running the `nbexec` job under arq.
+
+- The user guide includes a new tutorial for using the Noteburst web API.
### Other changes
diff --git a/Dockerfile b/Dockerfile
index 256ddfb..665d975 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -14,7 +14,8 @@
# - Runs a non-root user.
# - Sets up the entrypoint and port.
-FROM python:3.12.2-slim-bullseye as base-image
+
+FROM python:3.12.6-slim-bookworm AS base-image
# Update system packages
COPY scripts/install-base-packages.sh .
diff --git a/Makefile b/Makefile
index ea3b30e..acedfc9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,34 +1,48 @@
-# The dependencies need --allow-unsafe because kubernetes-asyncio and
-# (transitively) pre-commit depends on setuptools, which is normally not
-# allowed to appear in a hashed dependency file.
+.PHONY: help
+help:
+ @echo "Make targets for example"
+ @echo "make init - Set up dev environment"
+ @echo "make run - Start a local development instance"
+ @echo "make update - Update pinned dependencies and run make init"
+ @echo "make update-deps - Update pinned dependencies"
+ @echo "make update-deps-no-hashes - Pin dependencies without hashes"
+
+.PHONY: init
+init:
+ pip install --upgrade uv
+ uv pip install -r requirements/main.txt -r requirements/dev.txt \
+ -r requirements/tox.txt
+ uv pip install --editable .
+ rm -rf .tox
+ uv pip install --upgrade pre-commit
+ pre-commit install
+
+.PHONY: run
+run:
+ tox run -e run
+
+.PHONY: update
+update: update-deps init
+
.PHONY: update-deps
update-deps:
- pip install --upgrade pip-tools pip setuptools
- pip-compile --upgrade --resolver=backtracking --build-isolation \
- --allow-unsafe --generate-hashes \
+ pip install --upgrade uv
+ uv pip install --upgrade pre-commit
+ pre-commit autoupdate
+ uv pip compile --upgrade --generate-hashes \
--output-file requirements/main.txt requirements/main.in
- pip-compile --upgrade --resolver=backtracking --build-isolation \
- --allow-unsafe --generate-hashes \
+ uv pip compile --upgrade --generate-hashes \
--output-file requirements/dev.txt requirements/dev.in
+ uv pip compile --upgrade --generate-hashes \
+ --output-file requirements/tox.txt requirements/tox.in
# Useful for testing against a Git version of Safir.
.PHONY: update-deps-no-hashes
update-deps-no-hashes:
- pip install --upgrade pip-tools pip setuptools
- pip-compile --upgrade --resolver=backtracking --build-isolation \
- --allow-unsafe \
+ pip install --upgrade uv
+ uv pip compile --upgrade \
--output-file requirements/main.txt requirements/main.in
- pip-compile --upgrade --resolver=backtracking --build-isolation \
- --allow-unsafe \
+ uv pip compile --upgrade \
--output-file requirements/dev.txt requirements/dev.in
-
-.PHONY: init
-init:
- pip install --editable .
- pip install --upgrade -r requirements/main.txt -r requirements/dev.txt
- rm -rf .tox
- pip install --upgrade tox tox-docker
- pre-commit install
-
-.PHONY: update
-update: update-deps init
+ uv pip compile --upgrade \
+ --output-file requirements/tox.txt requirements/tox.in
diff --git a/docs/_rst_epilog.rst b/docs/_rst_epilog.rst
index e0de42e..2c76083 100644
--- a/docs/_rst_epilog.rst
+++ b/docs/_rst_epilog.rst
@@ -3,4 +3,4 @@
.. _pytest: https://docs.pytest.org/en/latest/
.. _tox: https://tox.readthedocs.io/en/latest/
.. _httpie: https://httpie.io/cli
-.. _`Rubin Science Platform environment`:
+.. _`Rubin Science Platform environment`:
diff --git a/docs/user-guide/environment-variables.rst b/docs/user-guide/environment-variables.rst
index 7458d20..0d4b542 100644
--- a/docs/user-guide/environment-variables.rst
+++ b/docs/user-guide/environment-variables.rst
@@ -21,7 +21,7 @@ See the `Phalanx documentation for Noteburst =1.0.0
diff --git a/requirements/dev.txt b/requirements/dev.txt
index eec7522..f7d6aa8 100644
--- a/requirements/dev.txt
+++ b/requirements/dev.txt
@@ -1,148 +1,169 @@
-#
-# This file is autogenerated by pip-compile with Python 3.12
-# by the following command:
-#
-# pip-compile --allow-unsafe --generate-hashes --output-file=requirements/dev.txt requirements/dev.in
-#
-alabaster==0.7.13 \
- --hash=sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3 \
- --hash=sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2
+# This file was autogenerated by uv via the following command:
+# uv pip compile --generate-hashes --output-file requirements/dev.txt requirements/dev.in
+alabaster==1.0.0 \
+ --hash=sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e \
+ --hash=sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b
# via sphinx
-annotated-types==0.6.0 \
- --hash=sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43 \
- --hash=sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d
+annotated-types==0.7.0 \
+ --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \
+ --hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89
# via
# -c requirements/main.txt
# pydantic
-anyio==4.2.0 \
- --hash=sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee \
- --hash=sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f
+anyio==4.6.2.post1 \
+ --hash=sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c \
+ --hash=sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d
# via
# -c requirements/main.txt
# httpx
+appnope==0.1.4 \
+ --hash=sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee \
+ --hash=sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c
+ # via ipykernel
asgi-lifespan==2.1.0 \
--hash=sha256:5e2effaf0bfe39829cf2d64e7ecc47c7d86d676a6599f7afba378c31f5e3a308 \
--hash=sha256:ed840706680e28428c01e14afb3875d7d76d3206f3d5b2f2294e059b5c23804f
# via -r requirements/dev.in
-attrs==23.2.0 \
- --hash=sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30 \
- --hash=sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1
+asttokens==2.4.1 \
+ --hash=sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24 \
+ --hash=sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0
+ # via stack-data
+attrs==24.2.0 \
+ --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \
+ --hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2
# via
# -c requirements/main.txt
# jsonschema
+ # jupyter-cache
# referencing
# scriv
-babel==2.14.0 \
- --hash=sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363 \
- --hash=sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287
+babel==2.16.0 \
+ --hash=sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b \
+ --hash=sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316
# via sphinx
-beautifulsoup4==4.12.2 \
- --hash=sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da \
- --hash=sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a
+beautifulsoup4==4.12.3 \
+ --hash=sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051 \
+ --hash=sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed
# via pydata-sphinx-theme
-certifi==2023.11.17 \
- --hash=sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1 \
- --hash=sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474
+certifi==2024.8.30 \
+ --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \
+ --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9
# via
# -c requirements/main.txt
# httpcore
# httpx
# requests
+ # sphinx-prompt
cfgv==3.4.0 \
--hash=sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9 \
--hash=sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560
# via pre-commit
-charset-normalizer==3.3.2 \
- --hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
- --hash=sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087 \
- --hash=sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786 \
- --hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
- --hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
- --hash=sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185 \
- --hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
- --hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
- --hash=sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519 \
- --hash=sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898 \
- --hash=sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269 \
- --hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
- --hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
- --hash=sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6 \
- --hash=sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8 \
- --hash=sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a \
- --hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
- --hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
- --hash=sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714 \
- --hash=sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2 \
- --hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
- --hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
- --hash=sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d \
- --hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
- --hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
- --hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
- --hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
- --hash=sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d \
- --hash=sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a \
- --hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
- --hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
- --hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
- --hash=sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0 \
- --hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
- --hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
- --hash=sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac \
- --hash=sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25 \
- --hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
- --hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
- --hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
- --hash=sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2 \
- --hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
- --hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
- --hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
- --hash=sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99 \
- --hash=sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c \
- --hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
- --hash=sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811 \
- --hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
- --hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
- --hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
- --hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
- --hash=sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04 \
- --hash=sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c \
- --hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
- --hash=sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458 \
- --hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
- --hash=sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99 \
- --hash=sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985 \
- --hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
- --hash=sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238 \
- --hash=sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f \
- --hash=sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d \
- --hash=sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796 \
- --hash=sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a \
- --hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
- --hash=sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8 \
- --hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
- --hash=sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5 \
- --hash=sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5 \
- --hash=sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711 \
- --hash=sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4 \
- --hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
- --hash=sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c \
- --hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
- --hash=sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4 \
- --hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
- --hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
- --hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
- --hash=sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c \
- --hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
- --hash=sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8 \
- --hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
- --hash=sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b \
- --hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
- --hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
- --hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
- --hash=sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33 \
- --hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519 \
- --hash=sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561
+charset-normalizer==3.4.0 \
+ --hash=sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621 \
+ --hash=sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6 \
+ --hash=sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8 \
+ --hash=sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912 \
+ --hash=sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c \
+ --hash=sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b \
+ --hash=sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d \
+ --hash=sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d \
+ --hash=sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95 \
+ --hash=sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e \
+ --hash=sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565 \
+ --hash=sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64 \
+ --hash=sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab \
+ --hash=sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be \
+ --hash=sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e \
+ --hash=sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907 \
+ --hash=sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0 \
+ --hash=sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2 \
+ --hash=sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62 \
+ --hash=sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62 \
+ --hash=sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23 \
+ --hash=sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc \
+ --hash=sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284 \
+ --hash=sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca \
+ --hash=sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455 \
+ --hash=sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858 \
+ --hash=sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b \
+ --hash=sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594 \
+ --hash=sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc \
+ --hash=sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db \
+ --hash=sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b \
+ --hash=sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea \
+ --hash=sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6 \
+ --hash=sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920 \
+ --hash=sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749 \
+ --hash=sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7 \
+ --hash=sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd \
+ --hash=sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99 \
+ --hash=sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242 \
+ --hash=sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee \
+ --hash=sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129 \
+ --hash=sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2 \
+ --hash=sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51 \
+ --hash=sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee \
+ --hash=sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8 \
+ --hash=sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b \
+ --hash=sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613 \
+ --hash=sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742 \
+ --hash=sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe \
+ --hash=sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3 \
+ --hash=sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5 \
+ --hash=sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631 \
+ --hash=sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7 \
+ --hash=sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15 \
+ --hash=sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c \
+ --hash=sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea \
+ --hash=sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417 \
+ --hash=sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250 \
+ --hash=sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88 \
+ --hash=sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca \
+ --hash=sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa \
+ --hash=sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99 \
+ --hash=sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149 \
+ --hash=sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41 \
+ --hash=sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574 \
+ --hash=sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0 \
+ --hash=sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f \
+ --hash=sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d \
+ --hash=sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654 \
+ --hash=sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3 \
+ --hash=sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19 \
+ --hash=sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90 \
+ --hash=sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578 \
+ --hash=sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9 \
+ --hash=sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1 \
+ --hash=sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51 \
+ --hash=sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719 \
+ --hash=sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236 \
+ --hash=sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a \
+ --hash=sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c \
+ --hash=sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade \
+ --hash=sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944 \
+ --hash=sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc \
+ --hash=sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6 \
+ --hash=sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6 \
+ --hash=sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27 \
+ --hash=sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6 \
+ --hash=sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2 \
+ --hash=sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12 \
+ --hash=sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf \
+ --hash=sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114 \
+ --hash=sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7 \
+ --hash=sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf \
+ --hash=sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d \
+ --hash=sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b \
+ --hash=sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed \
+ --hash=sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03 \
+ --hash=sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4 \
+ --hash=sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67 \
+ --hash=sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365 \
+ --hash=sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a \
+ --hash=sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748 \
+ --hash=sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b \
+ --hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079 \
+ --hash=sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482
# via requests
click==8.1.7 \
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
@@ -151,81 +172,126 @@ click==8.1.7 \
# -c requirements/main.txt
# click-log
# documenteer
+ # jupyter-cache
# scriv
# uvicorn
click-log==0.4.0 \
--hash=sha256:3970f8570ac54491237bcdb3d8ab5e3eef6c057df29f8c3d1151a51a9c23b975 \
--hash=sha256:a43e394b528d52112af599f2fc9e4b7cf3c15f94e53581f74fa6867e68c91756
# via scriv
-coverage[toml]==7.4.0 \
- --hash=sha256:04387a4a6ecb330c1878907ce0dc04078ea72a869263e53c72a1ba5bbdf380ca \
- --hash=sha256:0676cd0ba581e514b7f726495ea75aba3eb20899d824636c6f59b0ed2f88c471 \
- --hash=sha256:0e8d06778e8fbffccfe96331a3946237f87b1e1d359d7fbe8b06b96c95a5407a \
- --hash=sha256:0eb3c2f32dabe3a4aaf6441dde94f35687224dfd7eb2a7f47f3fd9428e421058 \
- --hash=sha256:109f5985182b6b81fe33323ab4707011875198c41964f014579cf82cebf2bb85 \
- --hash=sha256:13eaf476ec3e883fe3e5fe3707caeb88268a06284484a3daf8250259ef1ba143 \
- --hash=sha256:164fdcc3246c69a6526a59b744b62e303039a81e42cfbbdc171c91a8cc2f9446 \
- --hash=sha256:26776ff6c711d9d835557ee453082025d871e30b3fd6c27fcef14733f67f0590 \
- --hash=sha256:26f66da8695719ccf90e794ed567a1549bb2644a706b41e9f6eae6816b398c4a \
- --hash=sha256:29f3abe810930311c0b5d1a7140f6395369c3db1be68345638c33eec07535105 \
- --hash=sha256:316543f71025a6565677d84bc4df2114e9b6a615aa39fb165d697dba06a54af9 \
- --hash=sha256:36b0ea8ab20d6a7564e89cb6135920bc9188fb5f1f7152e94e8300b7b189441a \
- --hash=sha256:3cc9d4bc55de8003663ec94c2f215d12d42ceea128da8f0f4036235a119c88ac \
- --hash=sha256:485e9f897cf4856a65a57c7f6ea3dc0d4e6c076c87311d4bc003f82cfe199d25 \
- --hash=sha256:5040148f4ec43644702e7b16ca864c5314ccb8ee0751ef617d49aa0e2d6bf4f2 \
- --hash=sha256:51456e6fa099a8d9d91497202d9563a320513fcf59f33991b0661a4a6f2ad450 \
- --hash=sha256:53d7d9158ee03956e0eadac38dfa1ec8068431ef8058fe6447043db1fb40d932 \
- --hash=sha256:5a10a4920def78bbfff4eff8a05c51be03e42f1c3735be42d851f199144897ba \
- --hash=sha256:5b14b4f8760006bfdb6e08667af7bc2d8d9bfdb648351915315ea17645347137 \
- --hash=sha256:5b2ccb7548a0b65974860a78c9ffe1173cfb5877460e5a229238d985565574ae \
- --hash=sha256:697d1317e5290a313ef0d369650cfee1a114abb6021fa239ca12b4849ebbd614 \
- --hash=sha256:6ae8c9d301207e6856865867d762a4b6fd379c714fcc0607a84b92ee63feff70 \
- --hash=sha256:707c0f58cb1712b8809ece32b68996ee1e609f71bd14615bd8f87a1293cb610e \
- --hash=sha256:74775198b702868ec2d058cb92720a3c5a9177296f75bd97317c787daf711505 \
- --hash=sha256:756ded44f47f330666843b5781be126ab57bb57c22adbb07d83f6b519783b870 \
- --hash=sha256:76f03940f9973bfaee8cfba70ac991825611b9aac047e5c80d499a44079ec0bc \
- --hash=sha256:79287fd95585ed36e83182794a57a46aeae0b64ca53929d1176db56aacc83451 \
- --hash=sha256:799c8f873794a08cdf216aa5d0531c6a3747793b70c53f70e98259720a6fe2d7 \
- --hash=sha256:7d360587e64d006402b7116623cebf9d48893329ef035278969fa3bbf75b697e \
- --hash=sha256:80b5ee39b7f0131ebec7968baa9b2309eddb35b8403d1869e08f024efd883566 \
- --hash=sha256:815ac2d0f3398a14286dc2cea223a6f338109f9ecf39a71160cd1628786bc6f5 \
- --hash=sha256:83c2dda2666fe32332f8e87481eed056c8b4d163fe18ecc690b02802d36a4d26 \
- --hash=sha256:846f52f46e212affb5bcf131c952fb4075b55aae6b61adc9856222df89cbe3e2 \
- --hash=sha256:936d38794044b26c99d3dd004d8af0035ac535b92090f7f2bb5aa9c8e2f5cd42 \
- --hash=sha256:9864463c1c2f9cb3b5db2cf1ff475eed2f0b4285c2aaf4d357b69959941aa555 \
- --hash=sha256:995ea5c48c4ebfd898eacb098164b3cc826ba273b3049e4a889658548e321b43 \
- --hash=sha256:a1526d265743fb49363974b7aa8d5899ff64ee07df47dd8d3e37dcc0818f09ed \
- --hash=sha256:a56de34db7b7ff77056a37aedded01b2b98b508227d2d0979d373a9b5d353daa \
- --hash=sha256:a7c97726520f784239f6c62506bc70e48d01ae71e9da128259d61ca5e9788516 \
- --hash=sha256:b8e99f06160602bc64da35158bb76c73522a4010f0649be44a4e167ff8555952 \
- --hash=sha256:bb1de682da0b824411e00a0d4da5a784ec6496b6850fdf8c865c1d68c0e318dd \
- --hash=sha256:bf477c355274a72435ceb140dc42de0dc1e1e0bf6e97195be30487d8eaaf1a09 \
- --hash=sha256:bf635a52fc1ea401baf88843ae8708591aa4adff875e5c23220de43b1ccf575c \
- --hash=sha256:bfd5db349d15c08311702611f3dccbef4b4e2ec148fcc636cf8739519b4a5c0f \
- --hash=sha256:c530833afc4707fe48524a44844493f36d8727f04dcce91fb978c414a8556cc6 \
- --hash=sha256:cc6d65b21c219ec2072c1293c505cf36e4e913a3f936d80028993dd73c7906b1 \
- --hash=sha256:cd3c1e4cb2ff0083758f09be0f77402e1bdf704adb7f89108007300a6da587d0 \
- --hash=sha256:cfd2a8b6b0d8e66e944d47cdec2f47c48fef2ba2f2dff5a9a75757f64172857e \
- --hash=sha256:d0ca5c71a5a1765a0f8f88022c52b6b8be740e512980362f7fdbb03725a0d6b9 \
- --hash=sha256:e7defbb9737274023e2d7af02cac77043c86ce88a907c58f42b580a97d5bcca9 \
- --hash=sha256:e9d1bf53c4c8de58d22e0e956a79a5b37f754ed1ffdbf1a260d9dcfa2d8a325e \
- --hash=sha256:ea81d8f9691bb53f4fb4db603203029643caffc82bf998ab5b59ca05560f4c06
+comm==0.2.2 \
+ --hash=sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e \
+ --hash=sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3
+ # via ipykernel
+coverage==7.6.4 \
+ --hash=sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376 \
+ --hash=sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9 \
+ --hash=sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111 \
+ --hash=sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172 \
+ --hash=sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491 \
+ --hash=sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546 \
+ --hash=sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2 \
+ --hash=sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11 \
+ --hash=sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08 \
+ --hash=sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c \
+ --hash=sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2 \
+ --hash=sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963 \
+ --hash=sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613 \
+ --hash=sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0 \
+ --hash=sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db \
+ --hash=sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf \
+ --hash=sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73 \
+ --hash=sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117 \
+ --hash=sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1 \
+ --hash=sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e \
+ --hash=sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522 \
+ --hash=sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25 \
+ --hash=sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc \
+ --hash=sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea \
+ --hash=sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52 \
+ --hash=sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a \
+ --hash=sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07 \
+ --hash=sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06 \
+ --hash=sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa \
+ --hash=sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901 \
+ --hash=sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b \
+ --hash=sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17 \
+ --hash=sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0 \
+ --hash=sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21 \
+ --hash=sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19 \
+ --hash=sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5 \
+ --hash=sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51 \
+ --hash=sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3 \
+ --hash=sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3 \
+ --hash=sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f \
+ --hash=sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076 \
+ --hash=sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a \
+ --hash=sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718 \
+ --hash=sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba \
+ --hash=sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e \
+ --hash=sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27 \
+ --hash=sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e \
+ --hash=sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09 \
+ --hash=sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e \
+ --hash=sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70 \
+ --hash=sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f \
+ --hash=sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72 \
+ --hash=sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a \
+ --hash=sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef \
+ --hash=sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b \
+ --hash=sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b \
+ --hash=sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f \
+ --hash=sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806 \
+ --hash=sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b \
+ --hash=sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1 \
+ --hash=sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c \
+ --hash=sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858
# via
# -r requirements/dev.in
# pytest-cov
-distlib==0.3.8 \
- --hash=sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784 \
- --hash=sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64
+debugpy==1.8.7 \
+ --hash=sha256:11ad72eb9ddb436afb8337891a986302e14944f0f755fd94e90d0d71e9100bba \
+ --hash=sha256:171899588bcd412151e593bd40d9907133a7622cd6ecdbdb75f89d1551df13c2 \
+ --hash=sha256:18b8f731ed3e2e1df8e9cdaa23fb1fc9c24e570cd0081625308ec51c82efe42e \
+ --hash=sha256:29e1571c276d643757ea126d014abda081eb5ea4c851628b33de0c2b6245b037 \
+ --hash=sha256:2efb84d6789352d7950b03d7f866e6d180284bc02c7e12cb37b489b7083d81aa \
+ --hash=sha256:2f729228430ef191c1e4df72a75ac94e9bf77413ce5f3f900018712c9da0aaca \
+ --hash=sha256:45c30aaefb3e1975e8a0258f5bbd26cd40cde9bfe71e9e5a7ac82e79bad64e39 \
+ --hash=sha256:4b908291a1d051ef3331484de8e959ef3e66f12b5e610c203b5b75d2725613a7 \
+ --hash=sha256:4d27d842311353ede0ad572600c62e4bcd74f458ee01ab0dd3a1a4457e7e3706 \
+ --hash=sha256:57b00de1c8d2c84a61b90880f7e5b6deaf4c312ecbde3a0e8912f2a56c4ac9ae \
+ --hash=sha256:628a11f4b295ffb4141d8242a9bb52b77ad4a63a2ad19217a93be0f77f2c28c9 \
+ --hash=sha256:6a9d9d6d31846d8e34f52987ee0f1a904c7baa4912bf4843ab39dadf9b8f3e0d \
+ --hash=sha256:6e1c4ffb0c79f66e89dfd97944f335880f0d50ad29525dc792785384923e2211 \
+ --hash=sha256:703c1fd62ae0356e194f3e7b7a92acd931f71fe81c4b3be2c17a7b8a4b546ec2 \
+ --hash=sha256:85ce9c1d0eebf622f86cc68618ad64bf66c4fc3197d88f74bb695a416837dd55 \
+ --hash=sha256:90d93e4f2db442f8222dec5ec55ccfc8005821028982f1968ebf551d32b28907 \
+ --hash=sha256:93176e7672551cb5281577cdb62c63aadc87ec036f0c6a486f0ded337c504596 \
+ --hash=sha256:95fe04a573b8b22896c404365e03f4eda0ce0ba135b7667a1e57bd079793b96b \
+ --hash=sha256:a6cf2510740e0c0b4a40330640e4b454f928c7b99b0c9dbf48b11efba08a8cda \
+ --hash=sha256:b12515e04720e9e5c2216cc7086d0edadf25d7ab7e3564ec8b4521cf111b4f8c \
+ --hash=sha256:b6db2a370e2700557a976eaadb16243ec9c91bd46f1b3bb15376d7aaa7632c81 \
+ --hash=sha256:caf528ff9e7308b74a1749c183d6808ffbedbb9fb6af78b033c28974d9b8831f \
+ --hash=sha256:cba1d078cf2e1e0b8402e6bda528bf8fda7ccd158c3dba6c012b7897747c41a0 \
+ --hash=sha256:d050a1ec7e925f514f0f6594a1e522580317da31fbda1af71d1530d6ea1f2b40 \
+ --hash=sha256:da8df5b89a41f1fd31503b179d0a84a5fdb752dddd5b5388dbd1ae23cda31ce9 \
+ --hash=sha256:f2f4349a28e3228a42958f8ddaa6333d6f8282d5edaea456070e48609c5983b7
+ # via ipykernel
+decorator==5.1.1 \
+ --hash=sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330 \
+ --hash=sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186
+ # via ipython
+distlib==0.3.9 \
+ --hash=sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87 \
+ --hash=sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403
# via virtualenv
-documenteer[guide]==1.0.1 \
- --hash=sha256:0d6bf2947456fd3456d86790874d7aab24c8f33d5b69a1f4d40bfb88a714f900 \
- --hash=sha256:d581fb54b6205daec69b4515b5a71e15781dfff1c2dd1f59fa28de1d2b2d4eb9
- # via
- # -r requirements/dev.in
- # documenteer
-docutils==0.20.1 \
- --hash=sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6 \
- --hash=sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b
+documenteer==1.4.2 \
+ --hash=sha256:03a4cf3b8ffa4905c59662131f87afe77417238f10e9f01075d849f08a32e99d \
+ --hash=sha256:89756cf2026c3e70a36b9d2ecb69c38d58c320554f498be5955ddc815de4b035
+ # via -r requirements/dev.in
+docutils==0.21.2 \
+ --hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \
+ --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2
# via
# documenteer
# myst-parser
@@ -235,17 +301,25 @@ docutils==0.20.1 \
# sphinx-jinja
# sphinx-prompt
# sphinxcontrib-bibtex
-filelock==3.13.1 \
- --hash=sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e \
- --hash=sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c
+executing==2.1.0 \
+ --hash=sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf \
+ --hash=sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab
+ # via stack-data
+fastjsonschema==2.20.0 \
+ --hash=sha256:3d48fc5300ee96f5d116f10fe6f28d938e6008f59a6a025c2649475b87f76a23 \
+ --hash=sha256:5875f0b0fa7a0043a91e93a9b8f793bcbbba9691e7fd83dca95c28ba26d21f0a
+ # via nbformat
+filelock==3.16.1 \
+ --hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 \
+ --hash=sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435
# via virtualenv
gitdb==4.0.11 \
--hash=sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4 \
--hash=sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b
# via gitpython
-gitpython==3.1.40 \
- --hash=sha256:22b126e9ffb671fdd0c129796343a02bf67bf2994b35449ffc9321aa755e18a4 \
- --hash=sha256:cf14627d5a8049ffbf49915732e5eddbe8134c3bdb9d476e6182b676fc573f8a
+gitpython==3.1.43 \
+ --hash=sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c \
+ --hash=sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff
# via documenteer
h11==0.14.0 \
--hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \
@@ -254,65 +328,109 @@ h11==0.14.0 \
# -c requirements/main.txt
# httpcore
# uvicorn
-httpcore==1.0.2 \
- --hash=sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7 \
- --hash=sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535
+httpcore==1.0.6 \
+ --hash=sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f \
+ --hash=sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f
# via
# -c requirements/main.txt
# httpx
-httpx==0.26.0 \
- --hash=sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf \
- --hash=sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd
+httpx==0.27.2 \
+ --hash=sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0 \
+ --hash=sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2
# via
# -c requirements/main.txt
# -r requirements/dev.in
# respx
-identify==2.5.33 \
- --hash=sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d \
- --hash=sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34
+identify==2.6.1 \
+ --hash=sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0 \
+ --hash=sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98
# via pre-commit
-idna==3.6 \
- --hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \
- --hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
+idna==3.10 \
+ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \
+ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
# via
# -c requirements/main.txt
# anyio
# httpx
# requests
+ # sphinx-prompt
imagesize==1.4.1 \
--hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
--hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
# via sphinx
+importlib-metadata==8.5.0 \
+ --hash=sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b \
+ --hash=sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7
+ # via
+ # jupyter-cache
+ # myst-nb
iniconfig==2.0.0 \
--hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \
--hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374
# via pytest
-jinja2==3.1.2 \
- --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
- --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+ipykernel==6.29.5 \
+ --hash=sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5 \
+ --hash=sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215
+ # via myst-nb
+ipython==8.29.0 \
+ --hash=sha256:0188a1bd83267192123ccea7f4a8ed0a78910535dbaa3f37671dca76ebd429c8 \
+ --hash=sha256:40b60e15b22591450eef73e40a027cf77bd652e757523eebc5bd7c7c498290eb
+ # via
+ # ipykernel
+ # myst-nb
+jedi==0.19.1 \
+ --hash=sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd \
+ --hash=sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0
+ # via ipython
+jinja2==3.1.4 \
+ --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \
+ --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d
# via
# myst-parser
# scriv
# sphinx
# sphinx-jinja
# sphinxcontrib-redoc
-jsonschema==4.20.0 \
- --hash=sha256:4f614fd46d8d61258610998997743ec5492a648b33cf478c1ddc23ed4598a5fa \
- --hash=sha256:ed6231f0429ecf966f5bc8dfef245998220549cbbcf140f913b7464c52c3b6b3
- # via sphinxcontrib-redoc
-jsonschema-specifications==2023.12.1 \
- --hash=sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc \
- --hash=sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c
- # via jsonschema
-latexcodec==2.0.1 \
- --hash=sha256:2aa2551c373261cefe2ad3a8953a6d6533e68238d180eb4bb91d7964adb3fe9a \
- --hash=sha256:c277a193638dc7683c4c30f6684e3db728a06efb0dc9cf346db8bd0aa6c5d271
+jsonschema==4.23.0 \
+ --hash=sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4 \
+ --hash=sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566
+ # via
+ # -c requirements/main.txt
+ # nbformat
+ # sphinxcontrib-redoc
+jsonschema-specifications==2024.10.1 \
+ --hash=sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272 \
+ --hash=sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf
+ # via
+ # -c requirements/main.txt
+ # jsonschema
+jupyter-cache==1.0.0 \
+ --hash=sha256:594b1c4e29b488b36547e12477645f489dbdc62cc939b2408df5679f79245078 \
+ --hash=sha256:d0fa7d7533cd5798198d8889318269a8c1382ed3b22f622c09a9356521f48687
+ # via myst-nb
+jupyter-client==8.6.3 \
+ --hash=sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419 \
+ --hash=sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f
+ # via
+ # ipykernel
+ # nbclient
+jupyter-core==5.7.2 \
+ --hash=sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409 \
+ --hash=sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9
+ # via
+ # ipykernel
+ # jupyter-client
+ # nbclient
+ # nbformat
+latexcodec==3.0.0 \
+ --hash=sha256:6f3477ad5e61a0a99bd31a6a370c34e88733a6bad9c921a3ffcfacada12f41a7 \
+ --hash=sha256:917dc5fe242762cc19d963e6548b42d63a118028cdd3361d62397e3b638b6bc5
# via pybtex
-linkify-it-py==2.0.2 \
- --hash=sha256:19f3060727842c254c808e99d465c80c49d2c7306788140987a1a7a29b0d6ad2 \
- --hash=sha256:a3a24428f6c96f27370d7fe61d2ac0be09017be5190d68d8658233171f1b6541
+linkify-it-py==2.0.3 \
+ --hash=sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048 \
+ --hash=sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79
# via markdown-it-py
-markdown-it-py[linkify]==3.0.0 \
+markdown-it-py==3.0.0 \
--hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \
--hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb
# via
@@ -320,137 +438,214 @@ markdown-it-py[linkify]==3.0.0 \
# mdit-py-plugins
# myst-parser
# scriv
-markupsafe==2.1.3 \
- --hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
- --hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
- --hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
- --hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
- --hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
- --hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
- --hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
- --hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
- --hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
- --hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
- --hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
- --hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
- --hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
- --hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
- --hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
- --hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
- --hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
- --hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
- --hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
- --hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
- --hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
- --hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
- --hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
- --hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
- --hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
- --hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
- --hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
- --hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
- --hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
- --hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
- --hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
- --hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
- --hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
- --hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
- --hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
- --hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
- --hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
- --hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
- --hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
- --hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
- --hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
- --hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
- --hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
- --hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
- --hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
- --hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
- --hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
- --hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
- --hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
- --hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
- --hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
- --hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
- --hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
- --hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
- --hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
- --hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
- --hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
- --hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
- --hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
- --hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
+markupsafe==3.0.2 \
+ --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \
+ --hash=sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30 \
+ --hash=sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0 \
+ --hash=sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9 \
+ --hash=sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 \
+ --hash=sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13 \
+ --hash=sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028 \
+ --hash=sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca \
+ --hash=sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557 \
+ --hash=sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832 \
+ --hash=sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0 \
+ --hash=sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b \
+ --hash=sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579 \
+ --hash=sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a \
+ --hash=sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c \
+ --hash=sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff \
+ --hash=sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c \
+ --hash=sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22 \
+ --hash=sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094 \
+ --hash=sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb \
+ --hash=sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e \
+ --hash=sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5 \
+ --hash=sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a \
+ --hash=sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d \
+ --hash=sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a \
+ --hash=sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b \
+ --hash=sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8 \
+ --hash=sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225 \
+ --hash=sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c \
+ --hash=sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144 \
+ --hash=sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f \
+ --hash=sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87 \
+ --hash=sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d \
+ --hash=sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93 \
+ --hash=sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf \
+ --hash=sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158 \
+ --hash=sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84 \
+ --hash=sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb \
+ --hash=sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48 \
+ --hash=sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171 \
+ --hash=sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c \
+ --hash=sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6 \
+ --hash=sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd \
+ --hash=sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d \
+ --hash=sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1 \
+ --hash=sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d \
+ --hash=sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca \
+ --hash=sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a \
+ --hash=sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29 \
+ --hash=sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe \
+ --hash=sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798 \
+ --hash=sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c \
+ --hash=sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8 \
+ --hash=sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f \
+ --hash=sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f \
+ --hash=sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a \
+ --hash=sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178 \
+ --hash=sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0 \
+ --hash=sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79 \
+ --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \
+ --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50
# via jinja2
-mdit-py-plugins==0.4.0 \
- --hash=sha256:b51b3bb70691f57f974e257e367107857a93b36f322a9e6d44ca5bf28ec2def9 \
- --hash=sha256:d8ab27e9aed6c38aa716819fedfde15ca275715955f8a185a8e1cf90fb1d2c1b
+matplotlib-inline==0.1.7 \
+ --hash=sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90 \
+ --hash=sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca
+ # via
+ # ipykernel
+ # ipython
+mdit-py-plugins==0.4.2 \
+ --hash=sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636 \
+ --hash=sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5
# via myst-parser
mdurl==0.1.2 \
--hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
--hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
# via markdown-it-py
-mypy==1.8.0 \
- --hash=sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6 \
- --hash=sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d \
- --hash=sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02 \
- --hash=sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d \
- --hash=sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3 \
- --hash=sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3 \
- --hash=sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3 \
- --hash=sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66 \
- --hash=sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259 \
- --hash=sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835 \
- --hash=sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd \
- --hash=sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d \
- --hash=sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8 \
- --hash=sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07 \
- --hash=sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b \
- --hash=sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e \
- --hash=sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6 \
- --hash=sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae \
- --hash=sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9 \
- --hash=sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d \
- --hash=sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a \
- --hash=sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592 \
- --hash=sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218 \
- --hash=sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817 \
- --hash=sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4 \
- --hash=sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410 \
- --hash=sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55
+mypy==1.13.0 \
+ --hash=sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc \
+ --hash=sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e \
+ --hash=sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f \
+ --hash=sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74 \
+ --hash=sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a \
+ --hash=sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2 \
+ --hash=sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b \
+ --hash=sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73 \
+ --hash=sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e \
+ --hash=sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d \
+ --hash=sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d \
+ --hash=sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6 \
+ --hash=sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca \
+ --hash=sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d \
+ --hash=sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5 \
+ --hash=sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62 \
+ --hash=sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a \
+ --hash=sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc \
+ --hash=sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7 \
+ --hash=sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb \
+ --hash=sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7 \
+ --hash=sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732 \
+ --hash=sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80 \
+ --hash=sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a \
+ --hash=sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc \
+ --hash=sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2 \
+ --hash=sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0 \
+ --hash=sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24 \
+ --hash=sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7 \
+ --hash=sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b \
+ --hash=sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372 \
+ --hash=sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8
# via -r requirements/dev.in
mypy-extensions==1.0.0 \
--hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \
--hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782
# via mypy
-myst-parser==2.0.0 \
- --hash=sha256:7c36344ae39c8e740dad7fdabf5aa6fc4897a813083c6cc9990044eb93656b14 \
- --hash=sha256:ea929a67a6a0b1683cdbe19b8d2e724cd7643f8aa3e7bb18dd65beac3483bead
+myst-nb==1.1.2 \
+ --hash=sha256:961b4005657029ca89892a4c75edbf0856c54ceaf6172368b46bf7676c1f7700 \
+ --hash=sha256:9b7034e5d62640cb6daf03f9ca16ef45d0462fced27944c77aa3f98c7cdcd566
# via documenteer
-nodeenv==1.8.0 \
- --hash=sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2 \
- --hash=sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec
+myst-parser==4.0.0 \
+ --hash=sha256:851c9dfb44e36e56d15d05e72f02b80da21a9e0d07cba96baf5e2d476bb91531 \
+ --hash=sha256:b9317997552424448c6096c2558872fdb6f81d3ecb3a40ce84a7518798f3f28d
+ # via
+ # documenteer
+ # myst-nb
+nbclient==0.10.0 \
+ --hash=sha256:4b3f1b7dba531e498449c4db4f53da339c91d449dc11e9af3a43b4eb5c5abb09 \
+ --hash=sha256:f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f
+ # via
+ # jupyter-cache
+ # myst-nb
+nbformat==5.10.4 \
+ --hash=sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a \
+ --hash=sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b
+ # via
+ # jupyter-cache
+ # myst-nb
+ # nbclient
+nest-asyncio==1.6.0 \
+ --hash=sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe \
+ --hash=sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c
+ # via ipykernel
+nodeenv==1.9.1 \
+ --hash=sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f \
+ --hash=sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9
# via pre-commit
-packaging==23.2 \
- --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \
- --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7
+packaging==24.1 \
+ --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \
+ --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124
# via
# -c requirements/main.txt
+ # ipykernel
# pydata-sphinx-theme
# pytest
# sphinx
-platformdirs==4.1.0 \
- --hash=sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380 \
- --hash=sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420
- # via virtualenv
-pluggy==1.3.0 \
- --hash=sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12 \
- --hash=sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7
+parso==0.8.4 \
+ --hash=sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18 \
+ --hash=sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d
+ # via jedi
+pexpect==4.9.0 \
+ --hash=sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523 \
+ --hash=sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f
+ # via ipython
+platformdirs==4.3.6 \
+ --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \
+ --hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb
+ # via
+ # jupyter-core
+ # virtualenv
+pluggy==1.5.0 \
+ --hash=sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1 \
+ --hash=sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669
# via pytest
-pre-commit==3.6.0 \
- --hash=sha256:c255039ef399049a5544b6ce13d135caba8f2c28c3b4033277a788f434308376 \
- --hash=sha256:d30bad9abf165f7785c15a21a1f46da7d0677cb00ee7ff4c579fd38922efe15d
+pre-commit==4.0.1 \
+ --hash=sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2 \
+ --hash=sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878
# via -r requirements/dev.in
+prompt-toolkit==3.0.48 \
+ --hash=sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90 \
+ --hash=sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e
+ # via ipython
+psutil==6.1.0 \
+ --hash=sha256:000d1d1ebd634b4efb383f4034437384e44a6d455260aaee2eca1e9c1b55f047 \
+ --hash=sha256:045f00a43c737f960d273a83973b2511430d61f283a44c96bf13a6e829ba8fdc \
+ --hash=sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e \
+ --hash=sha256:1209036fbd0421afde505a4879dee3b2fd7b1e14fee81c0069807adcbbcca747 \
+ --hash=sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e \
+ --hash=sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a \
+ --hash=sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b \
+ --hash=sha256:5cd2bcdc75b452ba2e10f0e8ecc0b57b827dd5d7aaffbc6821b2a9a242823a76 \
+ --hash=sha256:6d3fbbc8d23fcdcb500d2c9f94e07b1342df8ed71b948a2649b5cb060a7c94ca \
+ --hash=sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688 \
+ --hash=sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e \
+ --hash=sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38 \
+ --hash=sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85 \
+ --hash=sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be \
+ --hash=sha256:c0e0c00aa18ca2d3b2b991643b799a15fc8f0563d2ebb6040f64ce8dc027b942 \
+ --hash=sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a \
+ --hash=sha256:ff34df86226c0227c52f38b919213157588a678d049688eded74c76c8ba4a5d0
+ # via ipykernel
+ptyprocess==0.7.0 \
+ --hash=sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35 \
+ --hash=sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220
+ # via pexpect
+pure-eval==0.2.3 \
+ --hash=sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0 \
+ --hash=sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42
+ # via stack-data
pybtex==0.24.0 \
--hash=sha256:818eae35b61733e5c007c3fcd2cfb75ed1bc8b4173c1f70b56cc4c0802d34755 \
--hash=sha256:e1e0c8c69998452fea90e9179aa2a98ab103f3eed894405b7264e517cc2fcc0f
@@ -461,118 +656,102 @@ pybtex-docutils==1.0.3 \
--hash=sha256:3a7ebdf92b593e00e8c1c538aa9a20bca5d92d84231124715acc964d51d93c6b \
--hash=sha256:8fd290d2ae48e32fcb54d86b0efb8d573198653c7e2447d5bec5847095f430b9
# via sphinxcontrib-bibtex
-pydantic==2.5.3 \
- --hash=sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a \
- --hash=sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4
+pydantic==2.9.2 \
+ --hash=sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f \
+ --hash=sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12
# via
# -c requirements/main.txt
# documenteer
-pydantic-core==2.14.6 \
- --hash=sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556 \
- --hash=sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e \
- --hash=sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411 \
- --hash=sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245 \
- --hash=sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c \
- --hash=sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66 \
- --hash=sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd \
- --hash=sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d \
- --hash=sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b \
- --hash=sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06 \
- --hash=sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948 \
- --hash=sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341 \
- --hash=sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0 \
- --hash=sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f \
- --hash=sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a \
- --hash=sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2 \
- --hash=sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51 \
- --hash=sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80 \
- --hash=sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8 \
- --hash=sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d \
- --hash=sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8 \
- --hash=sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb \
- --hash=sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590 \
- --hash=sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87 \
- --hash=sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534 \
- --hash=sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b \
- --hash=sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145 \
- --hash=sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba \
- --hash=sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b \
- --hash=sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2 \
- --hash=sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e \
- --hash=sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052 \
- --hash=sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622 \
- --hash=sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab \
- --hash=sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b \
- --hash=sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66 \
- --hash=sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e \
- --hash=sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4 \
- --hash=sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e \
- --hash=sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec \
- --hash=sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c \
- --hash=sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed \
- --hash=sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937 \
- --hash=sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f \
- --hash=sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9 \
- --hash=sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4 \
- --hash=sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96 \
- --hash=sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277 \
- --hash=sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23 \
- --hash=sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7 \
- --hash=sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b \
- --hash=sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91 \
- --hash=sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d \
- --hash=sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e \
- --hash=sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1 \
- --hash=sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2 \
- --hash=sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160 \
- --hash=sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9 \
- --hash=sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670 \
- --hash=sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7 \
- --hash=sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c \
- --hash=sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb \
- --hash=sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42 \
- --hash=sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d \
- --hash=sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8 \
- --hash=sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1 \
- --hash=sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6 \
- --hash=sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8 \
- --hash=sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf \
- --hash=sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e \
- --hash=sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a \
- --hash=sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9 \
- --hash=sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1 \
- --hash=sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40 \
- --hash=sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2 \
- --hash=sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d \
- --hash=sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f \
- --hash=sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f \
- --hash=sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af \
- --hash=sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7 \
- --hash=sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda \
- --hash=sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a \
- --hash=sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95 \
- --hash=sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0 \
- --hash=sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60 \
- --hash=sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149 \
- --hash=sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975 \
- --hash=sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4 \
- --hash=sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe \
- --hash=sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94 \
- --hash=sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03 \
- --hash=sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c \
- --hash=sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b \
- --hash=sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a \
- --hash=sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24 \
- --hash=sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391 \
- --hash=sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c \
- --hash=sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab \
- --hash=sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd \
- --hash=sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786 \
- --hash=sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08 \
- --hash=sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8 \
- --hash=sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6 \
- --hash=sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0 \
- --hash=sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421
+pydantic-core==2.23.4 \
+ --hash=sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36 \
+ --hash=sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05 \
+ --hash=sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071 \
+ --hash=sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327 \
+ --hash=sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c \
+ --hash=sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36 \
+ --hash=sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29 \
+ --hash=sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744 \
+ --hash=sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d \
+ --hash=sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec \
+ --hash=sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e \
+ --hash=sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e \
+ --hash=sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577 \
+ --hash=sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232 \
+ --hash=sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863 \
+ --hash=sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6 \
+ --hash=sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368 \
+ --hash=sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480 \
+ --hash=sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2 \
+ --hash=sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2 \
+ --hash=sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6 \
+ --hash=sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769 \
+ --hash=sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d \
+ --hash=sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2 \
+ --hash=sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84 \
+ --hash=sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166 \
+ --hash=sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271 \
+ --hash=sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5 \
+ --hash=sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb \
+ --hash=sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13 \
+ --hash=sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323 \
+ --hash=sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556 \
+ --hash=sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665 \
+ --hash=sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef \
+ --hash=sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb \
+ --hash=sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119 \
+ --hash=sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126 \
+ --hash=sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510 \
+ --hash=sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b \
+ --hash=sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87 \
+ --hash=sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f \
+ --hash=sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc \
+ --hash=sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8 \
+ --hash=sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21 \
+ --hash=sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f \
+ --hash=sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6 \
+ --hash=sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658 \
+ --hash=sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b \
+ --hash=sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3 \
+ --hash=sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb \
+ --hash=sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59 \
+ --hash=sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24 \
+ --hash=sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9 \
+ --hash=sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3 \
+ --hash=sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd \
+ --hash=sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753 \
+ --hash=sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55 \
+ --hash=sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad \
+ --hash=sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a \
+ --hash=sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605 \
+ --hash=sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e \
+ --hash=sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b \
+ --hash=sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433 \
+ --hash=sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8 \
+ --hash=sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07 \
+ --hash=sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728 \
+ --hash=sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0 \
+ --hash=sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327 \
+ --hash=sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555 \
+ --hash=sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64 \
+ --hash=sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6 \
+ --hash=sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea \
+ --hash=sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b \
+ --hash=sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df \
+ --hash=sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e \
+ --hash=sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd \
+ --hash=sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068 \
+ --hash=sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3 \
+ --hash=sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040 \
+ --hash=sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12 \
+ --hash=sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916 \
+ --hash=sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f \
+ --hash=sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f \
+ --hash=sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801 \
+ --hash=sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231 \
+ --hash=sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5 \
+ --hash=sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8 \
+ --hash=sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee \
+ --hash=sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607
# via
# -c requirements/main.txt
# pydantic
@@ -580,227 +759,388 @@ pydata-sphinx-theme==0.12.0 \
--hash=sha256:7a07c3ac1fb1cfbb5f7d1e147a9500fb120e329d610e0fa2caac4a645141bdd9 \
--hash=sha256:c17dbab67a3774f06f34f6378e896fcd0668cc8b5da1c1ba017e65cf1df0af58
# via documenteer
-pygments==2.17.2 \
- --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c \
- --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367
+pygments==2.18.0 \
+ --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \
+ --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a
# via
+ # ipython
# pydata-sphinx-theme
# sphinx
# sphinx-prompt
pylatexenc==2.10 \
--hash=sha256:3dd8fd84eb46dc30bee1e23eaab8d8fb5a7f507347b23e5f38ad9675c84f40d3
# via documenteer
-pytest==7.4.4 \
- --hash=sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280 \
- --hash=sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8
+pytest==8.3.3 \
+ --hash=sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181 \
+ --hash=sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2
# via
# -r requirements/dev.in
# pytest-asyncio
# pytest-cov
-pytest-asyncio==0.23.3 \
- --hash=sha256:37a9d912e8338ee7b4a3e917381d1c95bfc8682048cb0fbc35baba316ec1faba \
- --hash=sha256:af313ce900a62fbe2b1aed18e37ad757f1ef9940c6b6a88e2954de38d6b1fb9f
+pytest-asyncio==0.24.0 \
+ --hash=sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b \
+ --hash=sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276
# via -r requirements/dev.in
-pytest-cov==4.1.0 \
- --hash=sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6 \
- --hash=sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a
+pytest-cov==6.0.0 \
+ --hash=sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35 \
+ --hash=sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0
# via -r requirements/dev.in
-pyyaml==6.0.1 \
- --hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
- --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
- --hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \
- --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \
- --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \
- --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \
- --hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \
- --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \
- --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \
- --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \
- --hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \
- --hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \
- --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \
- --hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \
- --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \
- --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \
- --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \
- --hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \
- --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \
- --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \
- --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \
- --hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \
- --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \
- --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \
- --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \
- --hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \
- --hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
- --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
- --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
- --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
- --hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
- --hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \
- --hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \
- --hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \
- --hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \
- --hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \
- --hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \
- --hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \
- --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \
- --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \
- --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \
- --hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \
- --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \
- --hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \
- --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \
- --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \
- --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \
- --hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
- --hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
- --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
+python-dateutil==2.9.0.post0 \
+ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \
+ --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
+ # via
+ # -c requirements/main.txt
+ # jupyter-client
+pyyaml==6.0.2 \
+ --hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \
+ --hash=sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48 \
+ --hash=sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086 \
+ --hash=sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e \
+ --hash=sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133 \
+ --hash=sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5 \
+ --hash=sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484 \
+ --hash=sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee \
+ --hash=sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5 \
+ --hash=sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68 \
+ --hash=sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a \
+ --hash=sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf \
+ --hash=sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99 \
+ --hash=sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8 \
+ --hash=sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85 \
+ --hash=sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19 \
+ --hash=sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc \
+ --hash=sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a \
+ --hash=sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1 \
+ --hash=sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317 \
+ --hash=sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c \
+ --hash=sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631 \
+ --hash=sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d \
+ --hash=sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652 \
+ --hash=sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5 \
+ --hash=sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e \
+ --hash=sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b \
+ --hash=sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8 \
+ --hash=sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476 \
+ --hash=sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706 \
+ --hash=sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563 \
+ --hash=sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237 \
+ --hash=sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b \
+ --hash=sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083 \
+ --hash=sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180 \
+ --hash=sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425 \
+ --hash=sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e \
+ --hash=sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f \
+ --hash=sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725 \
+ --hash=sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183 \
+ --hash=sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab \
+ --hash=sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774 \
+ --hash=sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725 \
+ --hash=sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e \
+ --hash=sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5 \
+ --hash=sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d \
+ --hash=sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290 \
+ --hash=sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44 \
+ --hash=sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed \
+ --hash=sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4 \
+ --hash=sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba \
+ --hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \
+ --hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4
# via
# -c requirements/main.txt
# documenteer
+ # jupyter-cache
+ # myst-nb
# myst-parser
# pre-commit
# pybtex
+ # sphinxcontrib-mermaid
# sphinxcontrib-redoc
-referencing==0.32.0 \
- --hash=sha256:689e64fe121843dcfd57b71933318ef1f91188ffb45367332700a86ac8fd6161 \
- --hash=sha256:bdcd3efb936f82ff86f993093f6da7435c7de69a3b3a5a06678a6050184bee99
+pyzmq==26.2.0 \
+ --hash=sha256:007137c9ac9ad5ea21e6ad97d3489af654381324d5d3ba614c323f60dab8fae6 \
+ --hash=sha256:034da5fc55d9f8da09015d368f519478a52675e558c989bfcb5cf6d4e16a7d2a \
+ --hash=sha256:05590cdbc6b902101d0e65d6a4780af14dc22914cc6ab995d99b85af45362cc9 \
+ --hash=sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f \
+ --hash=sha256:0aca98bc423eb7d153214b2df397c6421ba6373d3397b26c057af3c904452e37 \
+ --hash=sha256:0bed0e799e6120b9c32756203fb9dfe8ca2fb8467fed830c34c877e25638c3fc \
+ --hash=sha256:0d987a3ae5a71c6226b203cfd298720e0086c7fe7c74f35fa8edddfbd6597eed \
+ --hash=sha256:0eaa83fc4c1e271c24eaf8fb083cbccef8fde77ec8cd45f3c35a9a123e6da097 \
+ --hash=sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d \
+ --hash=sha256:17bf5a931c7f6618023cdacc7081f3f266aecb68ca692adac015c383a134ca52 \
+ --hash=sha256:17c412bad2eb9468e876f556eb4ee910e62d721d2c7a53c7fa31e643d35352e6 \
+ --hash=sha256:18c8dc3b7468d8b4bdf60ce9d7141897da103c7a4690157b32b60acb45e333e6 \
+ --hash=sha256:1a534f43bc738181aa7cbbaf48e3eca62c76453a40a746ab95d4b27b1111a7d2 \
+ --hash=sha256:1c17211bc037c7d88e85ed8b7d8f7e52db6dc8eca5590d162717c654550f7282 \
+ --hash=sha256:1f3496d76b89d9429a656293744ceca4d2ac2a10ae59b84c1da9b5165f429ad3 \
+ --hash=sha256:1fcc03fa4997c447dce58264e93b5aa2d57714fbe0f06c07b7785ae131512732 \
+ --hash=sha256:226af7dcb51fdb0109f0016449b357e182ea0ceb6b47dfb5999d569e5db161d5 \
+ --hash=sha256:23f4aad749d13698f3f7b64aad34f5fc02d6f20f05999eebc96b89b01262fb18 \
+ --hash=sha256:25bf2374a2a8433633c65ccb9553350d5e17e60c8eb4de4d92cc6bd60f01d306 \
+ --hash=sha256:28ad5233e9c3b52d76196c696e362508959741e1a005fb8fa03b51aea156088f \
+ --hash=sha256:28c812d9757fe8acecc910c9ac9dafd2ce968c00f9e619db09e9f8f54c3a68a3 \
+ --hash=sha256:29c6a4635eef69d68a00321e12a7d2559fe2dfccfa8efae3ffb8e91cd0b36a8b \
+ --hash=sha256:29c7947c594e105cb9e6c466bace8532dc1ca02d498684128b339799f5248277 \
+ --hash=sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a \
+ --hash=sha256:2ae90ff9dad33a1cfe947d2c40cb9cb5e600d759ac4f0fd22616ce6540f72797 \
+ --hash=sha256:2c4a71d5d6e7b28a47a394c0471b7e77a0661e2d651e7ae91e0cab0a587859ca \
+ --hash=sha256:2ea4ad4e6a12e454de05f2949d4beddb52460f3de7c8b9d5c46fbb7d7222e02c \
+ --hash=sha256:2eb7735ee73ca1b0d71e0e67c3739c689067f055c764f73aac4cc8ecf958ee3f \
+ --hash=sha256:31507f7b47cc1ead1f6e86927f8ebb196a0bab043f6345ce070f412a59bf87b5 \
+ --hash=sha256:35cffef589bcdc587d06f9149f8d5e9e8859920a071df5a2671de2213bef592a \
+ --hash=sha256:367b4f689786fca726ef7a6c5ba606958b145b9340a5e4808132cc65759abd44 \
+ --hash=sha256:39887ac397ff35b7b775db7201095fc6310a35fdbae85bac4523f7eb3b840e20 \
+ --hash=sha256:3a495b30fc91db2db25120df5847d9833af237546fd59170701acd816ccc01c4 \
+ --hash=sha256:3b55a4229ce5da9497dd0452b914556ae58e96a4381bb6f59f1305dfd7e53fc8 \
+ --hash=sha256:402b190912935d3db15b03e8f7485812db350d271b284ded2b80d2e5704be780 \
+ --hash=sha256:43a47408ac52647dfabbc66a25b05b6a61700b5165807e3fbd40063fcaf46386 \
+ --hash=sha256:4661c88db4a9e0f958c8abc2b97472e23061f0bc737f6f6179d7a27024e1faa5 \
+ --hash=sha256:46a446c212e58456b23af260f3d9fb785054f3e3653dbf7279d8f2b5546b21c2 \
+ --hash=sha256:470d4a4f6d48fb34e92d768b4e8a5cc3780db0d69107abf1cd7ff734b9766eb0 \
+ --hash=sha256:49d34ab71db5a9c292a7644ce74190b1dd5a3475612eefb1f8be1d6961441971 \
+ --hash=sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b \
+ --hash=sha256:4d80b1dd99c1942f74ed608ddb38b181b87476c6a966a88a950c7dee118fdf50 \
+ --hash=sha256:4da04c48873a6abdd71811c5e163bd656ee1b957971db7f35140a2d573f6949c \
+ --hash=sha256:4f78c88905461a9203eac9faac157a2a0dbba84a0fd09fd29315db27be40af9f \
+ --hash=sha256:4ff9dc6bc1664bb9eec25cd17506ef6672d506115095411e237d571e92a58231 \
+ --hash=sha256:5506f06d7dc6ecf1efacb4a013b1f05071bb24b76350832c96449f4a2d95091c \
+ --hash=sha256:55cf66647e49d4621a7e20c8d13511ef1fe1efbbccf670811864452487007e08 \
+ --hash=sha256:5a509df7d0a83a4b178d0f937ef14286659225ef4e8812e05580776c70e155d5 \
+ --hash=sha256:5c2b3bfd4b9689919db068ac6c9911f3fcb231c39f7dd30e3138be94896d18e6 \
+ --hash=sha256:6835dd60355593de10350394242b5757fbbd88b25287314316f266e24c61d073 \
+ --hash=sha256:689c5d781014956a4a6de61d74ba97b23547e431e9e7d64f27d4922ba96e9d6e \
+ --hash=sha256:6a96179a24b14fa6428cbfc08641c779a53f8fcec43644030328f44034c7f1f4 \
+ --hash=sha256:6ace4f71f1900a548f48407fc9be59c6ba9d9aaf658c2eea6cf2779e72f9f317 \
+ --hash=sha256:6b274e0762c33c7471f1a7471d1a2085b1a35eba5cdc48d2ae319f28b6fc4de3 \
+ --hash=sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072 \
+ --hash=sha256:70fc7fcf0410d16ebdda9b26cbd8bf8d803d220a7f3522e060a69a9c87bf7bad \
+ --hash=sha256:7133d0a1677aec369d67dd78520d3fa96dd7f3dcec99d66c1762870e5ea1a50a \
+ --hash=sha256:7445be39143a8aa4faec43b076e06944b8f9d0701b669df4af200531b21e40bb \
+ --hash=sha256:76589c020680778f06b7e0b193f4b6dd66d470234a16e1df90329f5e14a171cd \
+ --hash=sha256:76589f2cd6b77b5bdea4fca5992dc1c23389d68b18ccc26a53680ba2dc80ff2f \
+ --hash=sha256:77eb0968da535cba0470a5165468b2cac7772cfb569977cff92e240f57e31bef \
+ --hash=sha256:794a4562dcb374f7dbbfb3f51d28fb40123b5a2abadee7b4091f93054909add5 \
+ --hash=sha256:7ad1bc8d1b7a18497dda9600b12dc193c577beb391beae5cd2349184db40f187 \
+ --hash=sha256:7f98f6dfa8b8ccaf39163ce872bddacca38f6a67289116c8937a02e30bbe9711 \
+ --hash=sha256:8423c1877d72c041f2c263b1ec6e34360448decfb323fa8b94e85883043ef988 \
+ --hash=sha256:8685fa9c25ff00f550c1fec650430c4b71e4e48e8d852f7ddcf2e48308038640 \
+ --hash=sha256:878206a45202247781472a2d99df12a176fef806ca175799e1c6ad263510d57c \
+ --hash=sha256:89289a5ee32ef6c439086184529ae060c741334b8970a6855ec0b6ad3ff28764 \
+ --hash=sha256:8ab5cad923cc95c87bffee098a27856c859bd5d0af31bd346035aa816b081fe1 \
+ --hash=sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1 \
+ --hash=sha256:8be4700cd8bb02cc454f630dcdf7cfa99de96788b80c51b60fe2fe1dac480289 \
+ --hash=sha256:8c997098cc65e3208eca09303630e84d42718620e83b733d0fd69543a9cab9cb \
+ --hash=sha256:8ea039387c10202ce304af74def5021e9adc6297067f3441d348d2b633e8166a \
+ --hash=sha256:8f7e66c7113c684c2b3f1c83cdd3376103ee0ce4c49ff80a648643e57fb22218 \
+ --hash=sha256:90412f2db8c02a3864cbfc67db0e3dcdbda336acf1c469526d3e869394fe001c \
+ --hash=sha256:92a78853d7280bffb93df0a4a6a2498cba10ee793cc8076ef797ef2f74d107cf \
+ --hash=sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7 \
+ --hash=sha256:9cb3a6460cdea8fe8194a76de8895707e61ded10ad0be97188cc8463ffa7e3a8 \
+ --hash=sha256:9dd8cd1aeb00775f527ec60022004d030ddc51d783d056e3e23e74e623e33726 \
+ --hash=sha256:9ed69074a610fad1c2fda66180e7b2edd4d31c53f2d1872bc2d1211563904cd9 \
+ --hash=sha256:9edda2df81daa129b25a39b86cb57dfdfe16f7ec15b42b19bfac503360d27a93 \
+ --hash=sha256:a2224fa4a4c2ee872886ed00a571f5e967c85e078e8e8c2530a2fb01b3309b88 \
+ --hash=sha256:a4f96f0d88accc3dbe4a9025f785ba830f968e21e3e2c6321ccdfc9aef755115 \
+ --hash=sha256:aedd5dd8692635813368e558a05266b995d3d020b23e49581ddd5bbe197a8ab6 \
+ --hash=sha256:aee22939bb6075e7afededabad1a56a905da0b3c4e3e0c45e75810ebe3a52672 \
+ --hash=sha256:b1d464cb8d72bfc1a3adc53305a63a8e0cac6bc8c5a07e8ca190ab8d3faa43c2 \
+ --hash=sha256:b8f86dd868d41bea9a5f873ee13bf5551c94cf6bc51baebc6f85075971fe6eea \
+ --hash=sha256:bc6bee759a6bddea5db78d7dcd609397449cb2d2d6587f48f3ca613b19410cfc \
+ --hash=sha256:bea2acdd8ea4275e1278350ced63da0b166421928276c7c8e3f9729d7402a57b \
+ --hash=sha256:bfa832bfa540e5b5c27dcf5de5d82ebc431b82c453a43d141afb1e5d2de025fa \
+ --hash=sha256:c0e6091b157d48cbe37bd67233318dbb53e1e6327d6fc3bb284afd585d141003 \
+ --hash=sha256:c3789bd5768ab5618ebf09cef6ec2b35fed88709b104351748a63045f0ff9797 \
+ --hash=sha256:c530e1eecd036ecc83c3407f77bb86feb79916d4a33d11394b8234f3bd35b940 \
+ --hash=sha256:c811cfcd6a9bf680236c40c6f617187515269ab2912f3d7e8c0174898e2519db \
+ --hash=sha256:c92d73464b886931308ccc45b2744e5968cbaade0b1d6aeb40d8ab537765f5bc \
+ --hash=sha256:cccba051221b916a4f5e538997c45d7d136a5646442b1231b916d0164067ea27 \
+ --hash=sha256:cdeabcff45d1c219636ee2e54d852262e5c2e085d6cb476d938aee8d921356b3 \
+ --hash=sha256:ced65e5a985398827cc9276b93ef6dfabe0273c23de8c7931339d7e141c2818e \
+ --hash=sha256:d049df610ac811dcffdc147153b414147428567fbbc8be43bb8885f04db39d98 \
+ --hash=sha256:dacd995031a01d16eec825bf30802fceb2c3791ef24bcce48fa98ce40918c27b \
+ --hash=sha256:ddf33d97d2f52d89f6e6e7ae66ee35a4d9ca6f36eda89c24591b0c40205a3629 \
+ --hash=sha256:ded0fc7d90fe93ae0b18059930086c51e640cdd3baebdc783a695c77f123dcd9 \
+ --hash=sha256:e3e0210287329272539eea617830a6a28161fbbd8a3271bf4150ae3e58c5d0e6 \
+ --hash=sha256:e6fa2e3e683f34aea77de8112f6483803c96a44fd726d7358b9888ae5bb394ec \
+ --hash=sha256:ea0eb6af8a17fa272f7b98d7bebfab7836a0d62738e16ba380f440fceca2d951 \
+ --hash=sha256:ea7f69de383cb47522c9c208aec6dd17697db7875a4674c4af3f8cfdac0bdeae \
+ --hash=sha256:eac5174677da084abf378739dbf4ad245661635f1600edd1221f150b165343f4 \
+ --hash=sha256:fc4f7a173a5609631bb0c42c23d12c49df3966f89f496a51d3eb0ec81f4519d6 \
+ --hash=sha256:fdb5b3e311d4d4b0eb8b3e8b4d1b0a512713ad7e6a68791d0923d1aec433d919
+ # via
+ # ipykernel
+ # jupyter-client
+referencing==0.35.1 \
+ --hash=sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c \
+ --hash=sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de
# via
+ # -c requirements/main.txt
# jsonschema
# jsonschema-specifications
-requests==2.31.0 \
- --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
- --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
+requests==2.32.3 \
+ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
+ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
# via
# documenteer
# scriv
# sphinx
-respx==0.20.2 \
- --hash=sha256:07cf4108b1c88b82010f67d3c831dae33a375c7b436e54d87737c7f9f99be643 \
- --hash=sha256:ab8e1cf6da28a5b2dd883ea617f8130f77f676736e6e9e4a25817ad116a172c9
+ # sphinxcontrib-youtube
+respx==0.21.1 \
+ --hash=sha256:05f45de23f0c785862a2c92a3e173916e8ca88e4caad715dd5f68584d6053c20 \
+ --hash=sha256:0bd7fe21bfaa52106caa1223ce61224cf30786985f17c63c5d71eff0307ee8af
# via -r requirements/dev.in
-rpds-py==0.16.2 \
- --hash=sha256:0474df4ade9a3b4af96c3d36eb81856cb9462e4c6657d4caecfd840d2a13f3c9 \
- --hash=sha256:071980663c273bf3d388fe5c794c547e6f35ba3335477072c713a3176bf14a60 \
- --hash=sha256:07aab64e2808c3ebac2a44f67e9dc0543812b715126dfd6fe4264df527556cb6 \
- --hash=sha256:088396c7c70e59872f67462fcac3ecbded5233385797021976a09ebd55961dfe \
- --hash=sha256:162d7cd9cd311c1b0ff1c55a024b8f38bd8aad1876b648821da08adc40e95734 \
- --hash=sha256:19f00f57fdd38db4bb5ad09f9ead1b535332dbf624200e9029a45f1f35527ebb \
- --hash=sha256:1bdbc5fcb04a7309074de6b67fa9bc4b418ab3fc435fec1f2779a0eced688d04 \
- --hash=sha256:1be2f033df1b8be8c3167ba3c29d5dca425592ee31e35eac52050623afba5772 \
- --hash=sha256:24f7a2eb3866a9e91f4599851e0c8d39878a470044875c49bd528d2b9b88361c \
- --hash=sha256:290a81cfbe4673285cdf140ec5cd1658ffbf63ab359f2b352ebe172e7cfa5bf0 \
- --hash=sha256:2946b120718eba9af2b4dd103affc1164a87b9e9ebff8c3e4c05d7b7a7e274e2 \
- --hash=sha256:2bd82db36cd70b3628c0c57d81d2438e8dd4b7b32a6a9f25f24ab0e657cb6c4e \
- --hash=sha256:2ddef620e70eaffebed5932ce754d539c0930f676aae6212f8e16cd9743dd365 \
- --hash=sha256:2e53b9b25cac9065328901713a7e9e3b12e4f57ef4280b370fbbf6fef2052eef \
- --hash=sha256:302bd4983bbd47063e452c38be66153760112f6d3635c7eeefc094299fa400a9 \
- --hash=sha256:349cb40897fd529ca15317c22c0eab67f5ac5178b5bd2c6adc86172045210acc \
- --hash=sha256:358dafc89ce3894c7f486c615ba914609f38277ef67f566abc4c854d23b997fa \
- --hash=sha256:35953f4f2b3216421af86fd236b7c0c65935936a94ea83ddbd4904ba60757773 \
- --hash=sha256:35ae5ece284cf36464eb160880018cf6088a9ac5ddc72292a6092b6ef3f4da53 \
- --hash=sha256:3b811d182ad17ea294f2ec63c0621e7be92a1141e1012383461872cead87468f \
- --hash=sha256:3da5a4c56953bdbf6d04447c3410309616c54433146ccdb4a277b9cb499bc10e \
- --hash=sha256:3dc6a7620ba7639a3db6213da61312cb4aa9ac0ca6e00dc1cbbdc21c2aa6eb57 \
- --hash=sha256:3f91df8e6dbb7360e176d1affd5fb0246d2b88d16aa5ebc7db94fd66b68b61da \
- --hash=sha256:4022b9dc620e14f30201a8a73898a873c8e910cb642bcd2f3411123bc527f6ac \
- --hash=sha256:413b9c17388bbd0d87a329d8e30c1a4c6e44e2bb25457f43725a8e6fe4161e9e \
- --hash=sha256:43d4dd5fb16eb3825742bad8339d454054261ab59fed2fbac84e1d84d5aae7ba \
- --hash=sha256:44627b6ca7308680a70766454db5249105fa6344853af6762eaad4158a2feebe \
- --hash=sha256:44a54e99a2b9693a37ebf245937fd6e9228b4cbd64b9cc961e1f3391ec6c7391 \
- --hash=sha256:47713dc4fce213f5c74ca8a1f6a59b622fc1b90868deb8e8e4d993e421b4b39d \
- --hash=sha256:495a14b72bbe217f2695dcd9b5ab14d4f8066a00f5d209ed94f0aca307f85f6e \
- --hash=sha256:4c46ad6356e1561f2a54f08367d1d2e70a0a1bb2db2282d2c1972c1d38eafc3b \
- --hash=sha256:4d6a9f052e72d493efd92a77f861e45bab2f6be63e37fa8ecf0c6fd1a58fedb0 \
- --hash=sha256:509b617ac787cd1149600e731db9274ebbef094503ca25158e6f23edaba1ca8f \
- --hash=sha256:5552f328eaef1a75ff129d4d0c437bf44e43f9436d3996e8eab623ea0f5fcf73 \
- --hash=sha256:5a80e2f83391ad0808b4646732af2a7b67550b98f0cae056cb3b40622a83dbb3 \
- --hash=sha256:5cf6af100ffb5c195beec11ffaa8cf8523057f123afa2944e6571d54da84cdc9 \
- --hash=sha256:5e6caa3809e50690bd92fa490f5c38caa86082c8c3315aa438bce43786d5e90d \
- --hash=sha256:5ef00873303d678aaf8b0627e111fd434925ca01c657dbb2641410f1cdaef261 \
- --hash=sha256:69ac7ea9897ec201ce68b48582f3eb34a3f9924488a5432a93f177bf76a82a7e \
- --hash=sha256:6a61226465bda9283686db8f17d02569a98e4b13c637be5a26d44aa1f1e361c2 \
- --hash=sha256:6d904c5693e08bad240f16d79305edba78276be87061c872a4a15e2c301fa2c0 \
- --hash=sha256:6dace7b26a13353e24613417ce2239491b40a6ad44e5776a18eaff7733488b44 \
- --hash=sha256:6df15846ee3fb2e6397fe25d7ca6624af9f89587f3f259d177b556fed6bebe2c \
- --hash=sha256:703d95c75a72e902544fda08e965885525e297578317989fd15a6ce58414b41d \
- --hash=sha256:726ac36e8a3bb8daef2fd482534cabc5e17334052447008405daca7ca04a3108 \
- --hash=sha256:781ef8bfc091b19960fc0142a23aedadafa826bc32b433fdfe6fd7f964d7ef44 \
- --hash=sha256:80443fe2f7b3ea3934c5d75fb0e04a5dbb4a8e943e5ff2de0dec059202b70a8b \
- --hash=sha256:83640a5d7cd3bff694747d50436b8b541b5b9b9782b0c8c1688931d6ee1a1f2d \
- --hash=sha256:84c5a4d1f9dd7e2d2c44097fb09fffe728629bad31eb56caf97719e55575aa82 \
- --hash=sha256:882ce6e25e585949c3d9f9abd29202367175e0aab3aba0c58c9abbb37d4982ff \
- --hash=sha256:888a97002e986eca10d8546e3c8b97da1d47ad8b69726dcfeb3e56348ebb28a3 \
- --hash=sha256:8aad80645a011abae487d356e0ceb359f4938dfb6f7bcc410027ed7ae4f7bb8b \
- --hash=sha256:8cb6fe8ecdfffa0e711a75c931fb39f4ba382b4b3ccedeca43f18693864fe850 \
- --hash=sha256:8d6b6937ae9eac6d6c0ca3c42774d89fa311f55adff3970fb364b34abde6ed3d \
- --hash=sha256:90123853fc8b1747f80b0d354be3d122b4365a93e50fc3aacc9fb4c2488845d6 \
- --hash=sha256:96f957d6ab25a78b9e7fc9749d754b98eac825a112b4e666525ce89afcbd9ed5 \
- --hash=sha256:981d135c7cdaf6cd8eadae1c950de43b976de8f09d8e800feed307140d3d6d00 \
- --hash=sha256:9b32f742ce5b57201305f19c2ef7a184b52f6f9ba6871cc042c2a61f0d6b49b8 \
- --hash=sha256:9f0350ef2fba5f34eb0c9000ea328e51b9572b403d2f7f3b19f24085f6f598e8 \
- --hash=sha256:a297a4d08cc67c7466c873c78039d87840fb50d05473db0ec1b7b03d179bf322 \
- --hash=sha256:a3d7e2ea25d3517c6d7e5a1cc3702cffa6bd18d9ef8d08d9af6717fc1c700eed \
- --hash=sha256:a4b682c5775d6a3d21e314c10124599976809455ee67020e8e72df1769b87bc3 \
- --hash=sha256:a4ebb8b20bd09c5ce7884c8f0388801100f5e75e7f733b1b6613c713371feefc \
- --hash=sha256:a61f659665a39a4d17d699ab3593d7116d66e1e2e3f03ef3fb8f484e91908808 \
- --hash=sha256:a9880b4656efe36ccad41edc66789e191e5ee19a1ea8811e0aed6f69851a82f4 \
- --hash=sha256:ac08472f41ea77cd6a5dae36ae7d4ed3951d6602833af87532b556c1b4601d63 \
- --hash=sha256:adc0c3d6fc6ae35fee3e4917628983f6ce630d513cbaad575b4517d47e81b4bb \
- --hash=sha256:af27423662f32d7501a00c5e7342f7dbd1e4a718aea7a239781357d15d437133 \
- --hash=sha256:b2e75e17bd0bb66ee34a707da677e47c14ee51ccef78ed6a263a4cc965a072a1 \
- --hash=sha256:b634c5ec0103c5cbebc24ebac4872b045cccb9456fc59efdcf6fe39775365bd2 \
- --hash=sha256:b6f5549d6ed1da9bfe3631ca9483ae906f21410be2445b73443fa9f017601c6f \
- --hash=sha256:bd4b677d929cf1f6bac07ad76e0f2d5de367e6373351c01a9c0a39f6b21b4a8b \
- --hash=sha256:bf721ede3eb7b829e4a9b8142bd55db0bdc82902720548a703f7e601ee13bdc3 \
- --hash=sha256:c647ca87fc0ebe808a41de912e9a1bfef9acb85257e5d63691364ac16b81c1f0 \
- --hash=sha256:ca57468da2d9a660bcf8961637c85f2fbb2aa64d9bc3f9484e30c3f9f67b1dd7 \
- --hash=sha256:cad0f59ee3dc35526039f4bc23642d52d5f6616b5f687d846bfc6d0d6d486db0 \
- --hash=sha256:cc97f0640e91d7776530f06e6836c546c1c752a52de158720c4224c9e8053cad \
- --hash=sha256:ccd4e400309e1f34a5095bf9249d371f0fd60f8a3a5c4a791cad7b99ce1fd38d \
- --hash=sha256:cffa76b385dfe1e38527662a302b19ffb0e7f5cf7dd5e89186d2c94a22dd9d0c \
- --hash=sha256:d0dd7ed2f16df2e129496e7fbe59a34bc2d7fc8db443a606644d069eb69cbd45 \
- --hash=sha256:d452817e0d9c749c431a1121d56a777bd7099b720b3d1c820f1725cb40928f58 \
- --hash=sha256:d8dda2a806dfa4a9b795950c4f5cc56d6d6159f7d68080aedaff3bdc9b5032f5 \
- --hash=sha256:dcbe1f8dd179e4d69b70b1f1d9bb6fd1e7e1bdc9c9aad345cdeb332e29d40748 \
- --hash=sha256:e0441fb4fdd39a230477b2ca9be90868af64425bfe7b122b57e61e45737a653b \
- --hash=sha256:e04e56b4ca7a770593633556e8e9e46579d66ec2ada846b401252a2bdcf70a6d \
- --hash=sha256:e061de3b745fe611e23cd7318aec2c8b0e4153939c25c9202a5811ca911fd733 \
- --hash=sha256:e93ec1b300acf89730cf27975ef574396bc04edecc358e9bd116fb387a123239 \
- --hash=sha256:e9e557db6a177470316c82f023e5d571811c9a4422b5ea084c85da9aa3c035fc \
- --hash=sha256:eab36eae3f3e8e24b05748ec9acc66286662f5d25c52ad70cadab544e034536b \
- --hash=sha256:ec23fcad480e77ede06cf4127a25fc440f7489922e17fc058f426b5256ee0edb \
- --hash=sha256:ec2e1cf025b2c0f48ec17ff3e642661da7ee332d326f2e6619366ce8e221f018 \
- --hash=sha256:ed99b4f7179d2111702020fd7d156e88acd533f5a7d3971353e568b6051d5c97 \
- --hash=sha256:ee94cb58c0ba2c62ee108c2b7c9131b2c66a29e82746e8fa3aa1a1effbd3dcf1 \
- --hash=sha256:f19afcfc0dd0dca35694df441e9b0f95bc231b512f51bded3c3d8ca32153ec19 \
- --hash=sha256:f1b9d9260e06ea017feb7172976ab261e011c1dc2f8883c7c274f6b2aabfe01a \
- --hash=sha256:f28ac0e8e7242d140f99402a903a2c596ab71550272ae9247ad78f9a932b5698 \
- --hash=sha256:f42e25c016927e2a6b1ce748112c3ab134261fc2ddc867e92d02006103e1b1b7 \
- --hash=sha256:f4bd4578e44f26997e9e56c96dedc5f1af43cc9d16c4daa29c771a00b2a26851 \
- --hash=sha256:f811771019f063bbd0aa7bb72c8a934bc13ebacb4672d712fc1639cfd314cccc
+rpds-py==0.20.1 \
+ --hash=sha256:02a0629ec053fc013808a85178524e3cb63a61dbc35b22499870194a63578fb9 \
+ --hash=sha256:07924c1b938798797d60c6308fa8ad3b3f0201802f82e4a2c41bb3fafb44cc28 \
+ --hash=sha256:07f59760ef99f31422c49038964b31c4dfcfeb5d2384ebfc71058a7c9adae2d2 \
+ --hash=sha256:0a3a1e9ee9728b2c1734f65d6a1d376c6f2f6fdcc13bb007a08cc4b1ff576dc5 \
+ --hash=sha256:0a90c373ea2975519b58dece25853dbcb9779b05cc46b4819cb1917e3b3215b6 \
+ --hash=sha256:0ad56edabcdb428c2e33bbf24f255fe2b43253b7d13a2cdbf05de955217313e6 \
+ --hash=sha256:0b581f47257a9fce535c4567782a8976002d6b8afa2c39ff616edf87cbeff712 \
+ --hash=sha256:0f8f741b6292c86059ed175d80eefa80997125b7c478fb8769fd9ac8943a16c0 \
+ --hash=sha256:0fc212779bf8411667234b3cdd34d53de6c2b8b8b958e1e12cb473a5f367c338 \
+ --hash=sha256:13c56de6518e14b9bf6edde23c4c39dac5b48dcf04160ea7bce8fca8397cdf86 \
+ --hash=sha256:142c0a5124d9bd0e2976089484af5c74f47bd3298f2ed651ef54ea728d2ea42c \
+ --hash=sha256:14511a539afee6f9ab492b543060c7491c99924314977a55c98bfa2ee29ce78c \
+ --hash=sha256:15a842bb369e00295392e7ce192de9dcbf136954614124a667f9f9f17d6a216f \
+ --hash=sha256:16d4477bcb9fbbd7b5b0e4a5d9b493e42026c0bf1f06f723a9353f5153e75d30 \
+ --hash=sha256:1791ff70bc975b098fe6ecf04356a10e9e2bd7dc21fa7351c1742fdeb9b4966f \
+ --hash=sha256:19b73643c802f4eaf13d97f7855d0fb527fbc92ab7013c4ad0e13a6ae0ed23bd \
+ --hash=sha256:200a23239781f46149e6a415f1e870c5ef1e712939fe8fa63035cd053ac2638e \
+ --hash=sha256:2249280b870e6a42c0d972339e9cc22ee98730a99cd7f2f727549af80dd5a963 \
+ --hash=sha256:2b431c777c9653e569986ecf69ff4a5dba281cded16043d348bf9ba505486f36 \
+ --hash=sha256:2cc3712a4b0b76a1d45a9302dd2f53ff339614b1c29603a911318f2357b04dd2 \
+ --hash=sha256:2fbb0ffc754490aff6dabbf28064be47f0f9ca0b9755976f945214965b3ace7e \
+ --hash=sha256:32b922e13d4c0080d03e7b62991ad7f5007d9cd74e239c4b16bc85ae8b70252d \
+ --hash=sha256:36785be22066966a27348444b40389f8444671630063edfb1a2eb04318721e17 \
+ --hash=sha256:37fe0f12aebb6a0e3e17bb4cd356b1286d2d18d2e93b2d39fe647138458b4bcb \
+ --hash=sha256:3aea7eed3e55119635a74bbeb80b35e776bafccb70d97e8ff838816c124539f1 \
+ --hash=sha256:3c6afcf2338e7f374e8edc765c79fbcb4061d02b15dd5f8f314a4af2bdc7feb5 \
+ --hash=sha256:3ccb8ac2d3c71cda472b75af42818981bdacf48d2e21c36331b50b4f16930163 \
+ --hash=sha256:3d089d0b88996df627693639d123c8158cff41c0651f646cd8fd292c7da90eaf \
+ --hash=sha256:3dd645e2b0dcb0fd05bf58e2e54c13875847687d0b71941ad2e757e5d89d4356 \
+ --hash=sha256:3e310838a5801795207c66c73ea903deda321e6146d6f282e85fa7e3e4854804 \
+ --hash=sha256:42cbde7789f5c0bcd6816cb29808e36c01b960fb5d29f11e052215aa85497c93 \
+ --hash=sha256:483b29f6f7ffa6af845107d4efe2e3fa8fb2693de8657bc1849f674296ff6a5a \
+ --hash=sha256:4888e117dd41b9d34194d9e31631af70d3d526efc363085e3089ab1a62c32ed1 \
+ --hash=sha256:49fe9b04b6fa685bd39237d45fad89ba19e9163a1ccaa16611a812e682913496 \
+ --hash=sha256:4a5a844f68776a7715ecb30843b453f07ac89bad393431efbf7accca3ef599c1 \
+ --hash=sha256:4a916087371afd9648e1962e67403c53f9c49ca47b9680adbeef79da3a7811b0 \
+ --hash=sha256:4f676e21db2f8c72ff0936f895271e7a700aa1f8d31b40e4e43442ba94973899 \
+ --hash=sha256:518d2ca43c358929bf08f9079b617f1c2ca6e8848f83c1225c88caeac46e6cbc \
+ --hash=sha256:5265505b3d61a0f56618c9b941dc54dc334dc6e660f1592d112cd103d914a6db \
+ --hash=sha256:55cd1fa4ecfa6d9f14fbd97ac24803e6f73e897c738f771a9fe038f2f11ff07c \
+ --hash=sha256:58b1d5dd591973d426cbb2da5e27ba0339209832b2f3315928c9790e13f159e8 \
+ --hash=sha256:59240685e7da61fb78f65a9f07f8108e36a83317c53f7b276b4175dc44151684 \
+ --hash=sha256:5b48e790e0355865197ad0aca8cde3d8ede347831e1959e158369eb3493d2191 \
+ --hash=sha256:5d4eea0761e37485c9b81400437adb11c40e13ef513375bbd6973e34100aeb06 \
+ --hash=sha256:648386ddd1e19b4a6abab69139b002bc49ebf065b596119f8f37c38e9ecee8ff \
+ --hash=sha256:653647b8838cf83b2e7e6a0364f49af96deec64d2a6578324db58380cff82aca \
+ --hash=sha256:6740a3e8d43a32629bb9b009017ea5b9e713b7210ba48ac8d4cb6d99d86c8ee8 \
+ --hash=sha256:6889469bfdc1eddf489729b471303739bf04555bb151fe8875931f8564309afc \
+ --hash=sha256:68cb0a499f2c4a088fd2f521453e22ed3527154136a855c62e148b7883b99f9a \
+ --hash=sha256:6aa97af1558a9bef4025f8f5d8c60d712e0a3b13a2fe875511defc6ee77a1ab7 \
+ --hash=sha256:6b73c67850ca7cae0f6c56f71e356d7e9fa25958d3e18a64927c2d930859b8e4 \
+ --hash=sha256:6c8e9340ce5a52f95fa7d3b552b35c7e8f3874d74a03a8a69279fd5fca5dc751 \
+ --hash=sha256:6ca91093a4a8da4afae7fe6a222c3b53ee4eef433ebfee4d54978a103435159e \
+ --hash=sha256:754bbed1a4ca48479e9d4182a561d001bbf81543876cdded6f695ec3d465846b \
+ --hash=sha256:762703bdd2b30983c1d9e62b4c88664df4a8a4d5ec0e9253b0231171f18f6d75 \
+ --hash=sha256:78f0b6877bfce7a3d1ff150391354a410c55d3cdce386f862926a4958ad5ab7e \
+ --hash=sha256:7a07ced2b22f0cf0b55a6a510078174c31b6d8544f3bc00c2bcee52b3d613f74 \
+ --hash=sha256:7dca7081e9a0c3b6490a145593f6fe3173a94197f2cb9891183ef75e9d64c425 \
+ --hash=sha256:7e21b7031e17c6b0e445f42ccc77f79a97e2687023c5746bfb7a9e45e0921b84 \
+ --hash=sha256:7f5179583d7a6cdb981151dd349786cbc318bab54963a192692d945dd3f6435d \
+ --hash=sha256:83cba698cfb3c2c5a7c3c6bac12fe6c6a51aae69513726be6411076185a8b24a \
+ --hash=sha256:842c19a6ce894493563c3bd00d81d5100e8e57d70209e84d5491940fdb8b9e3a \
+ --hash=sha256:84b8382a90539910b53a6307f7c35697bc7e6ffb25d9c1d4e998a13e842a5e83 \
+ --hash=sha256:8ba6f89cac95c0900d932c9efb7f0fb6ca47f6687feec41abcb1bd5e2bd45535 \
+ --hash=sha256:8bbe951244a838a51289ee53a6bae3a07f26d4e179b96fc7ddd3301caf0518eb \
+ --hash=sha256:925d176a549f4832c6f69fa6026071294ab5910e82a0fe6c6228fce17b0706bd \
+ --hash=sha256:92b68b79c0da2a980b1c4197e56ac3dd0c8a149b4603747c4378914a68706979 \
+ --hash=sha256:93da1d3db08a827eda74356f9f58884adb254e59b6664f64cc04cdff2cc19b0d \
+ --hash=sha256:95f3b65d2392e1c5cec27cff08fdc0080270d5a1a4b2ea1d51d5f4a2620ff08d \
+ --hash=sha256:9c4cb04a16b0f199a8c9bf807269b2f63b7b5b11425e4a6bd44bd6961d28282c \
+ --hash=sha256:a624cc00ef2158e04188df5e3016385b9353638139a06fb77057b3498f794782 \
+ --hash=sha256:a649dfd735fff086e8a9d0503a9f0c7d01b7912a333c7ae77e1515c08c146dad \
+ --hash=sha256:a94e52537a0e0a85429eda9e49f272ada715506d3b2431f64b8a3e34eb5f3e75 \
+ --hash=sha256:aa7ac11e294304e615b43f8c441fee5d40094275ed7311f3420d805fde9b07b4 \
+ --hash=sha256:b41b6321805c472f66990c2849e152aff7bc359eb92f781e3f606609eac877ad \
+ --hash=sha256:b71b8666eeea69d6363248822078c075bac6ed135faa9216aa85f295ff009b1e \
+ --hash=sha256:b9c2fe36d1f758b28121bef29ed1dee9b7a2453e997528e7d1ac99b94892527c \
+ --hash=sha256:bb63804105143c7e24cee7db89e37cb3f3941f8e80c4379a0b355c52a52b6780 \
+ --hash=sha256:be5ef2f1fc586a7372bfc355986226484e06d1dc4f9402539872c8bb99e34b01 \
+ --hash=sha256:c142b88039b92e7e0cb2552e8967077e3179b22359e945574f5e2764c3953dcf \
+ --hash=sha256:c14937af98c4cc362a1d4374806204dd51b1e12dded1ae30645c298e5a5c4cb1 \
+ --hash=sha256:ca449520e7484534a2a44faf629362cae62b660601432d04c482283c47eaebab \
+ --hash=sha256:cd945871335a639275eee904caef90041568ce3b42f402c6959b460d25ae8732 \
+ --hash=sha256:d0b937b2a1988f184a3e9e577adaa8aede21ec0b38320d6009e02bd026db04fa \
+ --hash=sha256:d126b52e4a473d40232ec2052a8b232270ed1f8c9571aaf33f73a14cc298c24f \
+ --hash=sha256:d8761c3c891cc51e90bc9926d6d2f59b27beaf86c74622c8979380a29cc23ac3 \
+ --hash=sha256:d9ecb51120de61e4604650666d1f2b68444d46ae18fd492245a08f53ad2b7711 \
+ --hash=sha256:da584ff96ec95e97925174eb8237e32f626e7a1a97888cdd27ee2f1f24dd0ad8 \
+ --hash=sha256:dbcf360c9e3399b056a238523146ea77eeb2a596ce263b8814c900263e46031a \
+ --hash=sha256:dbddc10776ca7ebf2a299c41a4dde8ea0d8e3547bfd731cb87af2e8f5bf8962d \
+ --hash=sha256:dc73505153798c6f74854aba69cc75953888cf9866465196889c7cdd351e720c \
+ --hash=sha256:e13de156137b7095442b288e72f33503a469aa1980ed856b43c353ac86390519 \
+ --hash=sha256:e1791c4aabd117653530dccd24108fa03cc6baf21f58b950d0a73c3b3b29a350 \
+ --hash=sha256:e75ba609dba23f2c95b776efb9dd3f0b78a76a151e96f96cc5b6b1b0004de66f \
+ --hash=sha256:e79059d67bea28b53d255c1437b25391653263f0e69cd7dec170d778fdbca95e \
+ --hash=sha256:ecd27a66740ffd621d20b9a2f2b5ee4129a56e27bfb9458a3bcc2e45794c96cb \
+ --hash=sha256:f009c69bc8c53db5dfab72ac760895dc1f2bc1b62ab7408b253c8d1ec52459fc \
+ --hash=sha256:f16bc1334853e91ddaaa1217045dd7be166170beec337576818461268a3de67f \
+ --hash=sha256:f19169781dddae7478a32301b499b2858bc52fc45a112955e798ee307e294977 \
+ --hash=sha256:fa3060d885657abc549b2a0f8e1b79699290e5d83845141717c6c90c2df38311 \
+ --hash=sha256:fa41a64ac5b08b292906e248549ab48b69c5428f3987b09689ab2441f267d04d \
+ --hash=sha256:fbf15aff64a163db29a91ed0868af181d6f68ec1a3a7d5afcfe4501252840bad \
+ --hash=sha256:fe00a9057d100e69b4ae4a094203a708d65b0f345ed546fdef86498bf5390982
# via
+ # -c requirements/main.txt
# jsonschema
# referencing
+ruff==0.7.2 \
+ --hash=sha256:21aae53ab1490a52bf4e3bf520c10ce120987b047c494cacf4edad0ba0888da2 \
+ --hash=sha256:28bd8220f4d8f79d590db9e2f6a0674f75ddbc3847277dd44ac1f8d30684b828 \
+ --hash=sha256:2b14e77293380e475b4e3a7a368e14549288ed2931fce259a6f99978669e844f \
+ --hash=sha256:576305393998b7bd6c46018f8104ea3a9cb3fa7908c21d8580e3274a3b04b691 \
+ --hash=sha256:5b813ef26db1015953daf476202585512afd6a6862a02cde63f3bafb53d0b2d4 \
+ --hash=sha256:7b792468e9804a204be221b14257566669d1db5c00d6bb335996e5cd7004ba80 \
+ --hash=sha256:853277dbd9675810c6826dad7a428d52a11760744508340e66bf46f8be9701d9 \
+ --hash=sha256:9fd67094e77efbea932e62b5d2483006154794040abb3a5072e659096415ae1e \
+ --hash=sha256:b19fafe261bf741bca2764c14cbb4ee1819b67adb63ebc2db6401dcd652e3748 \
+ --hash=sha256:b73f873b5f52092e63ed540adefc3c36f1f803790ecf2590e1df8bf0a9f72cb8 \
+ --hash=sha256:bb8368cd45bba3f57bb29cbb8d64b4a33f8415d0149d2655c5c8539452ce7760 \
+ --hash=sha256:ccc7e0fc6e0cb3168443eeadb6445285abaae75142ee22b2b72c27d790ab60ba \
+ --hash=sha256:dba53ed84ac19ae4bfb4ea4bf0172550a2285fa27fbb13e3746f04c80f7fa088 \
+ --hash=sha256:dd8800cbe0254e06b8fec585e97554047fb82c894973f7ff18558eee33d1cb88 \
+ --hash=sha256:e00163fb897d35523c70d71a46fbaa43bf7bf9af0f4534c53ea5b96b2e03397b \
+ --hash=sha256:f3c54b538633482dc342e9b634d91168fe8cc56b30a4b4f99287f4e339103e88 \
+ --hash=sha256:fa993cfc9f0ff11187e82de874dfc3611df80852540331bc85c75809c93253a8 \
+ --hash=sha256:fd77877a4e43b3a98e5ef4715ba3862105e299af0c48942cc6d51ba3d97dc859
+ # via -r requirements/dev.in
scriv==1.5.1 \
--hash=sha256:30ae9ff8d144f8e0cf394c4e1d379542f1b3823767642955b54ec40dc00b32b6 \
--hash=sha256:a3adc657733b4124fcb54527a5f3daab0d3c300de82d0fd2b9b297b243151b78
# via -r requirements/dev.in
+setuptools==75.3.0 \
+ --hash=sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd \
+ --hash=sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686
+ # via
+ # documenteer
+ # sphinxcontrib-bibtex
six==1.16.0 \
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
# via
- # latexcodec
+ # -c requirements/main.txt
+ # asttokens
# pybtex
+ # python-dateutil
# sphinxcontrib-redoc
smmap==5.0.1 \
--hash=sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62 \
--hash=sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da
# via gitdb
-sniffio==1.3.0 \
- --hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \
- --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384
+sniffio==1.3.1 \
+ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \
+ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc
# via
# -c requirements/main.txt
# anyio
@@ -810,15 +1150,16 @@ snowballstemmer==2.2.0 \
--hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \
--hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a
# via sphinx
-soupsieve==2.5 \
- --hash=sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690 \
- --hash=sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7
+soupsieve==2.6 \
+ --hash=sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb \
+ --hash=sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9
# via beautifulsoup4
-sphinx==7.2.6 \
- --hash=sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560 \
- --hash=sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5
+sphinx==8.1.3 \
+ --hash=sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2 \
+ --hash=sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927
# via
# documenteer
+ # myst-nb
# myst-parser
# pydata-sphinx-theme
# sphinx-autodoc-typehints
@@ -827,55 +1168,52 @@ sphinx==7.2.6 \
# sphinx-design
# sphinx-jinja
# sphinx-prompt
- # sphinxcontrib-applehelp
# sphinxcontrib-bibtex
- # sphinxcontrib-devhelp
- # sphinxcontrib-htmlhelp
# sphinxcontrib-jquery
- # sphinxcontrib-qthelp
+ # sphinxcontrib-mermaid
# sphinxcontrib-redoc
- # sphinxcontrib-serializinghtml
+ # sphinxcontrib-youtube
# sphinxext-opengraph
# sphinxext-rediraffe
-sphinx-autodoc-typehints==1.25.2 \
- --hash=sha256:3cabc2537e17989b2f92e64a399425c4c8bf561ed73f087bc7414a5003616a50 \
- --hash=sha256:5ed05017d23ad4b937eab3bee9fae9ab0dd63f0b42aa360031f1fad47e47f673
+sphinx-autodoc-typehints==2.5.0 \
+ --hash=sha256:259e1026b218d563d72743f417fcc25906a9614897fe37f91bd8d7d58f748c3b \
+ --hash=sha256:53def4753239683835b19bfa8b68c021388bd48a096efcb02cdab508ece27363
# via documenteer
-sphinx-automodapi==0.16.0 \
- --hash=sha256:68fc47064804604b90aa27c047016e86aaf970981d90a0082d5b5dd2e9d38afd \
- --hash=sha256:6c673ef93066408e5ad3e2fa3533044d432a47fe6a826212b9ebf5f52a872554
+sphinx-automodapi==0.18.0 \
+ --hash=sha256:022860385590768f52d4f6e19abb83b2574772d2721fb4050ecdb6e593a1a440 \
+ --hash=sha256:7bf9d9a2cb67a5389c51071cfd86674ca3892ca5d5943f95de4553d6f35dddae
# via documenteer
sphinx-copybutton==0.5.2 \
--hash=sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd \
--hash=sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e
# via documenteer
-sphinx-design==0.5.0 \
- --hash=sha256:1af1267b4cea2eedd6724614f19dcc88fe2e15aff65d06b2f6252cee9c4f4c1e \
- --hash=sha256:e8e513acea6f92d15c6de3b34e954458f245b8e761b45b63950f65373352ab00
+sphinx-design==0.6.1 \
+ --hash=sha256:b11f37db1a802a183d61b159d9a202314d4d2fe29c163437001324fe2f19549c \
+ --hash=sha256:b44eea3719386d04d765c1a8257caca2b3e6f8421d7b3a5e742c0fd45f84e632
# via documenteer
sphinx-jinja==2.0.2 \
--hash=sha256:705ebeb9b7a6018ca3f93724315a7c1effa6ba3db44d630e7eaaa15e4ac081a8 \
--hash=sha256:c6232b59a894139770be1dc6d0b00a379e4288ce78157904e1f8473dea3e0718
# via documenteer
-sphinx-prompt==1.8.0 \
- --hash=sha256:369ecc633f0711886f9b3a078c83264245be1adf46abeeb9b88b5519e4b51007 \
- --hash=sha256:47482f86fcec29662fdfd23e7c04ef03582714195d01f5d565403320084372ed
+sphinx-prompt==1.9.0 \
+ --hash=sha256:471b3c6d466dce780a9b167d9541865fd4e9a80ed46e31b06a52a0529ae995a1 \
+ --hash=sha256:fd731446c03f043d1ff6df9f22414495b23067c67011cc21658ea8d36b3575fc
# via documenteer
-sphinxcontrib-applehelp==1.0.7 \
- --hash=sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d \
- --hash=sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa
+sphinxcontrib-applehelp==2.0.0 \
+ --hash=sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1 \
+ --hash=sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5
# via sphinx
-sphinxcontrib-bibtex==2.6.1 \
- --hash=sha256:046b49f070ae5276af34c1b8ddb9bc9562ef6de2f7a52d37a91cb8e53f54b863 \
- --hash=sha256:094c772098fe6b030cda8618c45722b2957cad0c04f328ba2b154aa08dfe720a
+sphinxcontrib-bibtex==2.6.3 \
+ --hash=sha256:7c790347ef1cb0edf30de55fc324d9782d085e89c52c2b8faafa082e08e23946 \
+ --hash=sha256:ff016b738fcc867df0f75c29e139b3b2158d26a2c802db27963cb128be3b75fb
# via documenteer
-sphinxcontrib-devhelp==1.0.5 \
- --hash=sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212 \
- --hash=sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f
+sphinxcontrib-devhelp==2.0.0 \
+ --hash=sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad \
+ --hash=sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2
# via sphinx
-sphinxcontrib-htmlhelp==2.0.4 \
- --hash=sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a \
- --hash=sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9
+sphinxcontrib-htmlhelp==2.1.0 \
+ --hash=sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8 \
+ --hash=sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9
# via sphinx
sphinxcontrib-jquery==4.1 \
--hash=sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a \
@@ -885,21 +1223,25 @@ sphinxcontrib-jsmath==1.0.1 \
--hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \
--hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8
# via sphinx
-sphinxcontrib-mermaid==0.9.2 \
- --hash=sha256:252ef13dd23164b28f16d8b0205cf184b9d8e2b714a302274d9f59eb708e77af \
- --hash=sha256:6795a72037ca55e65663d2a2c1a043d636dc3d30d418e56dd6087d1459d98a5d
+sphinxcontrib-mermaid==1.0.0 \
+ --hash=sha256:2e8ab67d3e1e2816663f9347d026a8dee4a858acdd4ad32dd1c808893db88146 \
+ --hash=sha256:60b72710ea02087f212028feb09711225fbc2e343a10d34822fe787510e1caa3
# via documenteer
-sphinxcontrib-qthelp==1.0.6 \
- --hash=sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d \
- --hash=sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4
+sphinxcontrib-qthelp==2.0.0 \
+ --hash=sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab \
+ --hash=sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb
# via sphinx
sphinxcontrib-redoc==1.6.0 \
--hash=sha256:e358edbe23927d36432dde748e978cf897283a331a03e93d3ef02e348dee4561
# via documenteer
-sphinxcontrib-serializinghtml==1.1.9 \
- --hash=sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54 \
- --hash=sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1
+sphinxcontrib-serializinghtml==2.0.0 \
+ --hash=sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331 \
+ --hash=sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d
# via sphinx
+sphinxcontrib-youtube==1.4.1 \
+ --hash=sha256:de9cb454f066d580a1e7ad64efae7dd9e12c1b1567a31faa330b1aeaeed40460 \
+ --hash=sha256:eb7871c8af47fd2b5c9727615354b7f95bce554be8be45b9fa8e5bc022f88059
+ # via documenteer
sphinxext-opengraph==0.9.1 \
--hash=sha256:b3b230cc6a5b5189139df937f0d9c7b23c7c204493b22646273687969dcb760e \
--hash=sha256:dd2868a1e7c9497977fbbf44cc0844a42af39ca65fe1bb0272518af225d06fc5
@@ -908,45 +1250,144 @@ sphinxext-rediraffe==0.2.7 \
--hash=sha256:651dcbfae5ffda9ffd534dfb8025f36120e5efb6ea1a33f5420023862b9f725d \
--hash=sha256:9e430a52d4403847f4ffb3a8dd6dfc34a9fe43525305131f52ed899743a5fd8c
# via documenteer
-tomlkit==0.12.3 \
- --hash=sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4 \
- --hash=sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba
+sqlalchemy==2.0.36 \
+ --hash=sha256:03e08af7a5f9386a43919eda9de33ffda16b44eb11f3b313e6822243770e9763 \
+ --hash=sha256:0572f4bd6f94752167adfd7c1bed84f4b240ee6203a95e05d1e208d488d0d436 \
+ --hash=sha256:07b441f7d03b9a66299ce7ccf3ef2900abc81c0db434f42a5694a37bd73870f2 \
+ --hash=sha256:1bc330d9d29c7f06f003ab10e1eaced295e87940405afe1b110f2eb93a233588 \
+ --hash=sha256:1e0d612a17581b6616ff03c8e3d5eff7452f34655c901f75d62bd86449d9750e \
+ --hash=sha256:23623166bfefe1487d81b698c423f8678e80df8b54614c2bf4b4cfcd7c711959 \
+ --hash=sha256:2519f3a5d0517fc159afab1015e54bb81b4406c278749779be57a569d8d1bb0d \
+ --hash=sha256:28120ef39c92c2dd60f2721af9328479516844c6b550b077ca450c7d7dc68575 \
+ --hash=sha256:37350015056a553e442ff672c2d20e6f4b6d0b2495691fa239d8aa18bb3bc908 \
+ --hash=sha256:39769a115f730d683b0eb7b694db9789267bcd027326cccc3125e862eb03bfd8 \
+ --hash=sha256:3c01117dd36800f2ecaa238c65365b7b16497adc1522bf84906e5710ee9ba0e8 \
+ --hash=sha256:3d6718667da04294d7df1670d70eeddd414f313738d20a6f1d1f379e3139a545 \
+ --hash=sha256:3dbb986bad3ed5ceaf090200eba750b5245150bd97d3e67343a3cfed06feecf7 \
+ --hash=sha256:4557e1f11c5f653ebfdd924f3f9d5ebfc718283b0b9beebaa5dd6b77ec290971 \
+ --hash=sha256:46331b00096a6db1fdc052d55b101dbbfc99155a548e20a0e4a8e5e4d1362855 \
+ --hash=sha256:4a121d62ebe7d26fec9155f83f8be5189ef1405f5973ea4874a26fab9f1e262c \
+ --hash=sha256:4f5e9cd989b45b73bd359f693b935364f7e1f79486e29015813c338450aa5a71 \
+ --hash=sha256:50aae840ebbd6cdd41af1c14590e5741665e5272d2fee999306673a1bb1fdb4d \
+ --hash=sha256:59b1ee96617135f6e1d6f275bbe988f419c5178016f3d41d3c0abb0c819f75bb \
+ --hash=sha256:59b8f3adb3971929a3e660337f5dacc5942c2cdb760afcabb2614ffbda9f9f72 \
+ --hash=sha256:66bffbad8d6271bb1cc2f9a4ea4f86f80fe5e2e3e501a5ae2a3dc6a76e604e6f \
+ --hash=sha256:69f93723edbca7342624d09f6704e7126b152eaed3cdbb634cb657a54332a3c5 \
+ --hash=sha256:6a440293d802d3011028e14e4226da1434b373cbaf4a4bbb63f845761a708346 \
+ --hash=sha256:72c28b84b174ce8af8504ca28ae9347d317f9dba3999e5981a3cd441f3712e24 \
+ --hash=sha256:79d2e78abc26d871875b419e1fd3c0bca31a1cb0043277d0d850014599626c2e \
+ --hash=sha256:7f2767680b6d2398aea7082e45a774b2b0767b5c8d8ffb9c8b683088ea9b29c5 \
+ --hash=sha256:8318f4776c85abc3f40ab185e388bee7a6ea99e7fa3a30686580b209eaa35c08 \
+ --hash=sha256:8958b10490125124463095bbdadda5aa22ec799f91958e410438ad6c97a7b793 \
+ --hash=sha256:8c78ac40bde930c60e0f78b3cd184c580f89456dd87fc08f9e3ee3ce8765ce88 \
+ --hash=sha256:90812a8933df713fdf748b355527e3af257a11e415b613dd794512461eb8a686 \
+ --hash=sha256:9bc633f4ee4b4c46e7adcb3a9b5ec083bf1d9a97c1d3854b92749d935de40b9b \
+ --hash=sha256:9e46ed38affdfc95d2c958de328d037d87801cfcbea6d421000859e9789e61c2 \
+ --hash=sha256:9fe53b404f24789b5ea9003fc25b9a3988feddebd7e7b369c8fac27ad6f52f28 \
+ --hash=sha256:a4e46a888b54be23d03a89be510f24a7652fe6ff660787b96cd0e57a4ebcb46d \
+ --hash=sha256:a86bfab2ef46d63300c0f06936bd6e6c0105faa11d509083ba8f2f9d237fb5b5 \
+ --hash=sha256:ac9dfa18ff2a67b09b372d5db8743c27966abf0e5344c555d86cc7199f7ad83a \
+ --hash=sha256:af148a33ff0349f53512a049c6406923e4e02bf2f26c5fb285f143faf4f0e46a \
+ --hash=sha256:b11d0cfdd2b095e7b0686cf5fabeb9c67fae5b06d265d8180715b8cfa86522e3 \
+ --hash=sha256:b2985c0b06e989c043f1dc09d4fe89e1616aadd35392aea2844f0458a989eacf \
+ --hash=sha256:b544ad1935a8541d177cb402948b94e871067656b3a0b9e91dbec136b06a2ff5 \
+ --hash=sha256:b5cc79df7f4bc3d11e4b542596c03826063092611e481fcf1c9dfee3c94355ef \
+ --hash=sha256:b817d41d692bf286abc181f8af476c4fbef3fd05e798777492618378448ee689 \
+ --hash=sha256:b81ee3d84803fd42d0b154cb6892ae57ea6b7c55d8359a02379965706c7efe6c \
+ --hash=sha256:be9812b766cad94a25bc63bec11f88c4ad3629a0cec1cd5d4ba48dc23860486b \
+ --hash=sha256:c245b1fbade9c35e5bd3b64270ab49ce990369018289ecfde3f9c318411aaa07 \
+ --hash=sha256:c3f3631693003d8e585d4200730616b78fafd5a01ef8b698f6967da5c605b3fa \
+ --hash=sha256:c4ae3005ed83f5967f961fd091f2f8c5329161f69ce8480aa8168b2d7fe37f06 \
+ --hash=sha256:c54a1e53a0c308a8e8a7dffb59097bff7facda27c70c286f005327f21b2bd6b1 \
+ --hash=sha256:d0ddd9db6e59c44875211bc4c7953a9f6638b937b0a88ae6d09eb46cced54eff \
+ --hash=sha256:dc022184d3e5cacc9579e41805a681187650e170eb2fd70e28b86192a479dcaa \
+ --hash=sha256:e32092c47011d113dc01ab3e1d3ce9f006a47223b18422c5c0d150af13a00687 \
+ --hash=sha256:f7b64e6ec3f02c35647be6b4851008b26cff592a95ecb13b6788a54ef80bbdd4 \
+ --hash=sha256:f942a799516184c855e1a32fbc7b29d7e571b52612647866d4ec1c3242578fcb \
+ --hash=sha256:f9511d8dd4a6e9271d07d150fb2f81874a3c8c95e11ff9af3a2dfc35fe42ee44 \
+ --hash=sha256:fd3a55deef00f689ce931d4d1b23fa9f04c880a48ee97af488fd215cf24e2a6c \
+ --hash=sha256:fddbe92b4760c6f5d48162aef14824add991aeda8ddadb3c31d56eb15ca69f8e \
+ --hash=sha256:fdf3386a801ea5aba17c6410dd1dc8d39cf454ca2565541b5ac42a84e1e28f53
+ # via jupyter-cache
+stack-data==0.6.3 \
+ --hash=sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9 \
+ --hash=sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695
+ # via ipython
+tabulate==0.9.0 \
+ --hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \
+ --hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f
+ # via jupyter-cache
+tomlkit==0.13.2 \
+ --hash=sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde \
+ --hash=sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79
# via documenteer
-types-pyyaml==6.0.12.12 \
- --hash=sha256:334373d392fde0fdf95af5c3f1661885fa10c52167b14593eb856289e1855062 \
- --hash=sha256:c05bc6c158facb0676674b7f11fe3960db4f389718e19e62bd2b84d6205cfd24
+tornado==6.4.1 \
+ --hash=sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8 \
+ --hash=sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f \
+ --hash=sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4 \
+ --hash=sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3 \
+ --hash=sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14 \
+ --hash=sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842 \
+ --hash=sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9 \
+ --hash=sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698 \
+ --hash=sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7 \
+ --hash=sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d \
+ --hash=sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4
+ # via
+ # ipykernel
+ # jupyter-client
+traitlets==5.14.3 \
+ --hash=sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7 \
+ --hash=sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f
+ # via
+ # comm
+ # ipykernel
+ # ipython
+ # jupyter-client
+ # jupyter-core
+ # matplotlib-inline
+ # nbclient
+ # nbformat
+types-pyyaml==6.0.12.20240917 \
+ --hash=sha256:392b267f1c0fe6022952462bf5d6523f31e37f6cea49b14cee7ad634b6301570 \
+ --hash=sha256:d1405a86f9576682234ef83bcb4e6fff7c9305c8b1fbad5e0bcd4f7dbdc9c587
# via -r requirements/dev.in
-typing-extensions==4.9.0 \
- --hash=sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783 \
- --hash=sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd
+typing-extensions==4.12.2 \
+ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
+ --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
# via
# -c requirements/main.txt
# mypy
+ # myst-nb
# pydantic
# pydantic-core
-uc-micro-py==1.0.2 \
- --hash=sha256:30ae2ac9c49f39ac6dce743bd187fcd2b574b16ca095fa74cd9396795c954c54 \
- --hash=sha256:8c9110c309db9d9e87302e2f4ad2c3152770930d88ab385cd544e7a7e75f3de0
+ # sqlalchemy
+uc-micro-py==1.0.3 \
+ --hash=sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a \
+ --hash=sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5
# via linkify-it-py
-urllib3==2.1.0 \
- --hash=sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3 \
- --hash=sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54
+urllib3==2.2.3 \
+ --hash=sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac \
+ --hash=sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9
# via
# documenteer
# requests
-uvicorn==0.25.0 \
- --hash=sha256:6dddbad1d7ee0f5140aba5ec138ddc9612c5109399903828b4874c9937f009c2 \
- --hash=sha256:ce107f5d9bd02b4636001a77a4e74aab5e1e2b146868ebbad565237145af444c
+ # sphinx-prompt
+uvicorn==0.32.0 \
+ --hash=sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82 \
+ --hash=sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e
# via
# -c requirements/main.txt
# -r requirements/dev.in
-virtualenv==20.25.0 \
- --hash=sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3 \
- --hash=sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b
+virtualenv==20.27.1 \
+ --hash=sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba \
+ --hash=sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4
# via pre-commit
-
-# The following packages are considered to be unsafe in a requirements file:
-setuptools==69.0.3 \
- --hash=sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05 \
- --hash=sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78
- # via nodeenv
+wcwidth==0.2.13 \
+ --hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 \
+ --hash=sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5
+ # via prompt-toolkit
+zipp==3.20.2 \
+ --hash=sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350 \
+ --hash=sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29
+ # via importlib-metadata
diff --git a/requirements/main.in b/requirements/main.in
index 1cac71b..cd319f0 100644
--- a/requirements/main.in
+++ b/requirements/main.in
@@ -17,5 +17,7 @@ safir[arq]
pydantic
pydantic_settings
PyYAML
+rubin-nublado-client
httpx
websockets
+humanize
diff --git a/requirements/main.txt b/requirements/main.txt
index 1e5baeb..6b8c6a1 100644
--- a/requirements/main.txt
+++ b/requirements/main.txt
@@ -1,9 +1,42 @@
-#
-# This file is autogenerated by pip-compile with Python 3.12
-# by the following command:
-#
-# pip-compile --allow-unsafe --generate-hashes --output-file=requirements/main.txt requirements/main.in
-#
+# This file was autogenerated by uv via the following command:
+# uv pip compile --generate-hashes --output-file requirements/main.txt requirements/main.in
+aiofiles==23.2.1 \
+ --hash=sha256:19297512c647d4b27a2cf7c34caa7e405c0d60b5560618a29a9fe027b18b0107 \
+ --hash=sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a
+ # via python-schema-registry-client
+aiokafka==0.12.0 \
+ --hash=sha256:04c8ad27d04d6c53a1859687015a5f4e58b1eb221e8a7342d6c6b04430def53e \
+ --hash=sha256:06f5889acf8e1a81d6e14adf035acb29afd1f5836447fa8fa23d3cbe8f7e8608 \
+ --hash=sha256:08c84b3894d97fd02fcc8886f394000d0f5ce771fab5c498ea2b0dd2f6b46d5b \
+ --hash=sha256:1158e630664d9abc74d8a7673bc70dc10737ff758e1457bebc1c05890f29ce2c \
+ --hash=sha256:24633931e05a9dc80555a2f845572b6845d2dcb1af12de27837b8602b1b8bc74 \
+ --hash=sha256:2c01abf9787b1c3f3af779ad8e76d5b74903f590593bc26f33ed48750503e7f7 \
+ --hash=sha256:42b2436c7c69384d210e9169fbfe339d9f49dbdcfddd8d51c79b9877de545e33 \
+ --hash=sha256:4aab2767dcc8923626d8d60c314f9ba633563249cff71750db5d70b6ec813da2 \
+ --hash=sha256:577c1c48b240e9eba57b3d2d806fb3d023a575334fc3953f063179170cc8964f \
+ --hash=sha256:5a907abcdf02430df0829ac80f25b8bb849630300fa01365c76e0ae49306f512 \
+ --hash=sha256:62423895b866f95b5ed8d88335295a37cc5403af64cb7cb0e234f88adc2dff94 \
+ --hash=sha256:63875fed922c8c7cf470d9b2a82e1b76b4a1baf2ae62e07486cf516fd09ff8f2 \
+ --hash=sha256:6c77f5953ff4b25c889aef26df1f28df66c58db7abb7f34ecbe48502e9a6d273 \
+ --hash=sha256:7a57fda053acd1b88c87803ad0381a1d2a29d36ec561550d11ce9154972b8e23 \
+ --hash=sha256:90511a2c4cf5f343fc2190575041fbc70171654ab0dae64b3bbabd012613bfa7 \
+ --hash=sha256:a5c827c8883cfe64bc49100de82862225714e1853432df69aba99f135969bb1b \
+ --hash=sha256:a9590554fae68ec80099beae5366f2494130535a1a3db0c4fa5ccb08f37f6e46 \
+ --hash=sha256:b01947553ff1120fa1cb1a05f2c3e5aa47a5378c720bafd09e6630ba18af02aa \
+ --hash=sha256:b8ddff02b1e981083dff6d1a80d4502e0e83e0e480faf1f881766ca6f23e8d22 \
+ --hash=sha256:bdc0a83eb386d2384325d6571f8ef65b4cfa205f8d1c16d7863e8d10cacd995a \
+ --hash=sha256:bea5710f7707ed12a7f8661ab38dfa80f5253a405de5ba228f457cc30404eb51 \
+ --hash=sha256:d7b815b2e5fed9912f1231be6196547a367b9eb3380b487ff5942f0c73a3fb5c \
+ --hash=sha256:d87b1a45c57bbb1c17d1900a74739eada27e4f4a0b0932ab3c5a8cbae8bbfe1e \
+ --hash=sha256:da8938eac2153ca767ac0144283b3df7e74bb4c0abc0c9a722f3ae63cfbf3a42 \
+ --hash=sha256:ddc5308c43d48af883667e2f950a0a9739ce2c9bfe69a0b55dc234f58b1b42d6 \
+ --hash=sha256:e3c8ec1c0606fa645462c7353dc3e4119cade20c4656efa2031682ffaad361c0 \
+ --hash=sha256:ed991c120fe19fd9439f564201dd746c4839700ef270dd4c3ee6d4895f64fe83 \
+ --hash=sha256:f96d7fd8fdb5f439f7e7860fd8ec37870265d0578475e82049bce60ab07ca045 \
+ --hash=sha256:f9e8ab97b935ca681a5f28cf22cf2b5112be86728876b3ec07e4ed5fc6c21f2d \
+ --hash=sha256:fdbd69ec70eea4a8dfaa5c35ff4852e90e1277fcc426b9380f0b499b77f13b16 \
+ --hash=sha256:ff63689cafcd6dd642a15de75b7ae121071d6162cccba16d091bcb28b3886307
+ # via safir
aioredis==1.3.1 \
--hash=sha256:15f8af30b044c771aee6787e5ec24694c048184c7b9e54c3b60c750a4b93273a \
--hash=sha256:b61808d7e97b7cd5a92ed574937a079c9387fdadd22bfbfa7ad2fd319ecc26e3
@@ -12,88 +45,114 @@ aioredlock==0.7.3 \
--hash=sha256:7432fe17cf2ce55292409f4e80d26af5ccbf1a09aa4566e30bcfc5dabd4b3e1f \
--hash=sha256:903727b26eb571c926018a8ae2b754c6c11861996410e3c4f1309872d2545440
# via -r requirements/main.in
-annotated-types==0.6.0 \
- --hash=sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43 \
- --hash=sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d
+annotated-types==0.7.0 \
+ --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \
+ --hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89
# via pydantic
-anyio==4.2.0 \
- --hash=sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee \
- --hash=sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f
+anyio==4.6.2.post1 \
+ --hash=sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c \
+ --hash=sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d
# via
+ # fast-depends
+ # faststream
# httpx
# starlette
# watchfiles
-arq==0.25.0 \
- --hash=sha256:d176ebadfba920c039dc578814d19b7814d67fa15f82fdccccaedb4330d65dae \
- --hash=sha256:db072d0f39c0bc06b436db67ae1f315c81abc1527563b828955670531815290b
- # via safir
-async-timeout==4.0.3 \
- --hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \
- --hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028
- # via aioredis
-attrs==23.2.0 \
- --hash=sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30 \
- --hash=sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1
- # via aioredlock
-certifi==2023.11.17 \
- --hash=sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1 \
- --hash=sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474
+arq==0.26.1 \
+ --hash=sha256:789d12ca7d69919bd2e641e44f3f14a38bd854daa7ded22cdd725796e8c65352 \
+ --hash=sha256:a4db5395c3aaefe0610074b0aa125ff3392aa90a2214973be566796a5819d9cf
+ # via safir-arq
+async-timeout==5.0.0 \
+ --hash=sha256:49675ec889daacfe65ff66d2dde7dd1447a6f4b2f23721022e4ba121f8772a85 \
+ --hash=sha256:904719a4bd6e0520047d0ddae220aabee67b877f7ca17bf8cea20f67f6247ae0
+ # via
+ # aiokafka
+ # aioredis
+attrs==24.2.0 \
+ --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \
+ --hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2
+ # via
+ # aioredlock
+ # jsonschema
+ # referencing
+casefy==0.1.7 \
+ --hash=sha256:6accce985a64b9edb2a610a29ac489d78fac80e52ff8f2d137e294f2f92b8027 \
+ --hash=sha256:ab05ff1c67f2a8e62d9f8986fa9a849416d61ac5413ec57d1f827b4f36589cf6
+ # via dataclasses-avroschema
+certifi==2024.8.30 \
+ --hash=sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8 \
+ --hash=sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9
# via
# httpcore
# httpx
-cffi==1.16.0 \
- --hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \
- --hash=sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a \
- --hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \
- --hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \
- --hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \
- --hash=sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36 \
- --hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \
- --hash=sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8 \
- --hash=sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed \
- --hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \
- --hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \
- --hash=sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324 \
- --hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \
- --hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \
- --hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \
- --hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \
- --hash=sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000 \
- --hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \
- --hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \
- --hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \
- --hash=sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c \
- --hash=sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe \
- --hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \
- --hash=sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098 \
- --hash=sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8 \
- --hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \
- --hash=sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0 \
- --hash=sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b \
- --hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \
- --hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \
- --hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \
- --hash=sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2 \
- --hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \
- --hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \
- --hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \
- --hash=sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f \
- --hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \
- --hash=sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4 \
- --hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \
- --hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \
- --hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \
- --hash=sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872 \
- --hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \
- --hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \
- --hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \
- --hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \
- --hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \
- --hash=sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b \
- --hash=sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4 \
- --hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \
- --hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \
- --hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357
+cffi==1.17.1 \
+ --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \
+ --hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \
+ --hash=sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1 \
+ --hash=sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15 \
+ --hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \
+ --hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \
+ --hash=sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8 \
+ --hash=sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36 \
+ --hash=sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17 \
+ --hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \
+ --hash=sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc \
+ --hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \
+ --hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \
+ --hash=sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702 \
+ --hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \
+ --hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \
+ --hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \
+ --hash=sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6 \
+ --hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \
+ --hash=sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b \
+ --hash=sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e \
+ --hash=sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be \
+ --hash=sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c \
+ --hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \
+ --hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \
+ --hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \
+ --hash=sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8 \
+ --hash=sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1 \
+ --hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \
+ --hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \
+ --hash=sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67 \
+ --hash=sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595 \
+ --hash=sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0 \
+ --hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \
+ --hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \
+ --hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \
+ --hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \
+ --hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \
+ --hash=sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3 \
+ --hash=sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16 \
+ --hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \
+ --hash=sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e \
+ --hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \
+ --hash=sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964 \
+ --hash=sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c \
+ --hash=sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576 \
+ --hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \
+ --hash=sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3 \
+ --hash=sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662 \
+ --hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \
+ --hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \
+ --hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \
+ --hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \
+ --hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \
+ --hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \
+ --hash=sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14 \
+ --hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \
+ --hash=sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9 \
+ --hash=sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7 \
+ --hash=sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382 \
+ --hash=sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a \
+ --hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \
+ --hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \
+ --hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \
+ --hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \
+ --hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \
+ --hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b
# via cryptography
click==8.1.7 \
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
@@ -102,46 +161,175 @@ click==8.1.7 \
# arq
# safir
# uvicorn
-cryptography==41.0.7 \
- --hash=sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960 \
- --hash=sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a \
- --hash=sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc \
- --hash=sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a \
- --hash=sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf \
- --hash=sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1 \
- --hash=sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39 \
- --hash=sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406 \
- --hash=sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a \
- --hash=sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a \
- --hash=sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c \
- --hash=sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be \
- --hash=sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15 \
- --hash=sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2 \
- --hash=sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d \
- --hash=sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157 \
- --hash=sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003 \
- --hash=sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248 \
- --hash=sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a \
- --hash=sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec \
- --hash=sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309 \
- --hash=sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7 \
- --hash=sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d
+cryptography==43.0.3 \
+ --hash=sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362 \
+ --hash=sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4 \
+ --hash=sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa \
+ --hash=sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83 \
+ --hash=sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff \
+ --hash=sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805 \
+ --hash=sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6 \
+ --hash=sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664 \
+ --hash=sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08 \
+ --hash=sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e \
+ --hash=sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18 \
+ --hash=sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f \
+ --hash=sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73 \
+ --hash=sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5 \
+ --hash=sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984 \
+ --hash=sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd \
+ --hash=sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3 \
+ --hash=sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e \
+ --hash=sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405 \
+ --hash=sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2 \
+ --hash=sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c \
+ --hash=sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995 \
+ --hash=sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73 \
+ --hash=sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16 \
+ --hash=sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7 \
+ --hash=sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd \
+ --hash=sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7
# via
# pyjwt
# safir
-fastapi==0.108.0 \
- --hash=sha256:5056e504ac6395bf68493d71fcfc5352fdbd5fda6f88c21f6420d80d81163296 \
- --hash=sha256:8c7bc6d315da963ee4cdb605557827071a9a7f95aeb8fcdd3bde48cdc8764dd7
+dacite==1.8.1 \
+ --hash=sha256:cc31ad6fdea1f49962ea42db9421772afe01ac5442380d9a99fcf3d188c61afe
+ # via dataclasses-avroschema
+dataclasses-avroschema==0.64.2 \
+ --hash=sha256:4be3f4f97c583a6de8b1782a7aff60741fd772a821aeb58b68604d5cc4421307 \
+ --hash=sha256:875f23a0ac2069e52acb84b1979c8549f3716421f683d3a69e9df960a9ef778b
+ # via safir
+fast-depends==2.4.12 \
+ --hash=sha256:9393e6de827f7afa0141e54fa9553b737396aaf06bd0040e159d1f790487b16d \
+ --hash=sha256:9e5d110ddc962329e46c9b35e5fe65655984247a13ee3ca5a33186db7d2d75c2
+ # via faststream
+fastapi==0.115.4 \
+ --hash=sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742 \
+ --hash=sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349
# via
# -r requirements/main.in
# safir
+fastavro==1.9.7 \
+ --hash=sha256:0b2f9bafa167cb4d1c3dd17565cb5bf3d8c0759e42620280d1760f1e778e07fc \
+ --hash=sha256:13e11c6cb28626da85290933027cd419ce3f9ab8e45410ef24ce6b89d20a1f6c \
+ --hash=sha256:17de68aae8c2525f5631d80f2b447a53395cdc49134f51b0329a5497277fc2d2 \
+ --hash=sha256:1d09227d1f48f13281bd5ceac958650805aef9a4ef4f95810128c1f9be1df736 \
+ --hash=sha256:2af559f30383b79cf7d020a6b644c42ffaed3595f775fe8f3d7f80b1c43dfdc5 \
+ --hash=sha256:2db993ae6cdc63e25eadf9f93c9e8036f9b097a3e61d19dca42536dcc5c4d8b3 \
+ --hash=sha256:2fcce036c6aa06269fc6a0428050fcb6255189997f5e1a728fc461e8b9d3e26b \
+ --hash=sha256:3b683693c8a85ede496ebebe115be5d7870c150986e34a0442a20d88d7771224 \
+ --hash=sha256:4e1289b731214a7315884c74b2ec058b6e84380ce9b18b8af5d387e64b18fc44 \
+ --hash=sha256:536f5644737ad21d18af97d909dba099b9e7118c237be7e4bd087c7abde7e4f0 \
+ --hash=sha256:56304401d2f4f69f5b498bdd1552c13ef9a644d522d5de0dc1d789cf82f47f73 \
+ --hash=sha256:58f76a5c9a312fbd37b84e49d08eb23094d36e10d43bc5df5187bc04af463feb \
+ --hash=sha256:6312fa99deecc319820216b5e1b1bd2d7ebb7d6f221373c74acfddaee64e8e60 \
+ --hash=sha256:7313def3aea3dacface0a8b83f6d66e49a311149aa925c89184a06c1ef99785d \
+ --hash=sha256:76d9d96f98052615ab465c63ba8b76ed59baf2e3341b7b169058db104cbe2aa0 \
+ --hash=sha256:7c911366c625d0a997eafe0aa83ffbc6fd00d8fd4543cb39a97c6f3b8120ea87 \
+ --hash=sha256:912283ed48578a103f523817fdf0c19b1755cea9b4a6387b73c79ecb8f8f84fc \
+ --hash=sha256:919f3549e07a8a8645a2146f23905955c35264ac809f6c2ac18142bc5b9b6022 \
+ --hash=sha256:9be089be8c00f68e343bbc64ca6d9a13e5e5b0ba8aa52bcb231a762484fb270e \
+ --hash=sha256:9de1fa832a4d9016724cd6facab8034dc90d820b71a5d57c7e9830ffe90f31e4 \
+ --hash=sha256:b525c363e267ed11810aaad8fbdbd1c3bd8837d05f7360977d72a65ab8c6e1fa \
+ --hash=sha256:b6b2ccdc78f6afc18c52e403ee68c00478da12142815c1bd8a00973138a166d0 \
+ --hash=sha256:cc811fb4f7b5ae95f969cda910241ceacf82e53014c7c7224df6f6e0ca97f52f \
+ --hash=sha256:d576eccfd60a18ffa028259500df67d338b93562c6700e10ef68bbd88e499731 \
+ --hash=sha256:e87d04b235b29f7774d226b120da2ca4e60b9e6fdf6747daef7f13f218b3517a \
+ --hash=sha256:eac69666270a76a3a1d0444f39752061195e79e146271a568777048ffbd91a27 \
+ --hash=sha256:ec2e96bdabd58427fe683329b3d79f42c7b4f4ff6b3644664a345a655ac2c0a1 \
+ --hash=sha256:ec8499dc276c2d2ef0a68c0f1ad11782b2b956a921790a36bf4c18df2b8d4020 \
+ --hash=sha256:edc28ab305e3c424de5ac5eb87b48d1e07eddb6aa08ef5948fcda33cc4d995ce \
+ --hash=sha256:ee9bf23c157bd7dcc91ea2c700fa3bd924d9ec198bb428ff0b47fa37fe160659 \
+ --hash=sha256:fb8749e419a85f251bf1ac87d463311874972554d25d4a0b19f6bdc56036d7cf
+ # via
+ # dataclasses-avroschema
+ # python-schema-registry-client
+faststream==0.5.28 \
+ --hash=sha256:620f3edd2b85ac3d329726907540027abebc939ea7f16d209ef18de7d6e82f49 \
+ --hash=sha256:67794ffa8054169488f211832c50c3a992d897ebba415032a327372e019bda4c
+ # via safir
gidgethub==5.3.0 \
--hash=sha256:4dd92f2252d12756b13f9dd15cde322bfb0d625b6fb5d680da1567ec74b462c0 \
--hash=sha256:9ece7d37fbceb819b80560e7ed58f936e48a65d37ec5f56db79145156b426a25
# via safir
-gunicorn==21.2.0 \
- --hash=sha256:3213aa5e8c24949e792bcacfc176fef362e7aac80b76c56f6b5122bf350722f0 \
- --hash=sha256:88ec8bff1d634f98e61b9f65bc4bf3cd918a90806c6f5c48bc5603849ec81033
+greenlet==3.1.1 \
+ --hash=sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e \
+ --hash=sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7 \
+ --hash=sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01 \
+ --hash=sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1 \
+ --hash=sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159 \
+ --hash=sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563 \
+ --hash=sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83 \
+ --hash=sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9 \
+ --hash=sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395 \
+ --hash=sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa \
+ --hash=sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942 \
+ --hash=sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1 \
+ --hash=sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441 \
+ --hash=sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22 \
+ --hash=sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9 \
+ --hash=sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0 \
+ --hash=sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba \
+ --hash=sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3 \
+ --hash=sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1 \
+ --hash=sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6 \
+ --hash=sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291 \
+ --hash=sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39 \
+ --hash=sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d \
+ --hash=sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467 \
+ --hash=sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475 \
+ --hash=sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef \
+ --hash=sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c \
+ --hash=sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511 \
+ --hash=sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c \
+ --hash=sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822 \
+ --hash=sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a \
+ --hash=sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8 \
+ --hash=sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d \
+ --hash=sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01 \
+ --hash=sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145 \
+ --hash=sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80 \
+ --hash=sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13 \
+ --hash=sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e \
+ --hash=sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b \
+ --hash=sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1 \
+ --hash=sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef \
+ --hash=sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc \
+ --hash=sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff \
+ --hash=sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120 \
+ --hash=sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437 \
+ --hash=sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd \
+ --hash=sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981 \
+ --hash=sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36 \
+ --hash=sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a \
+ --hash=sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798 \
+ --hash=sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7 \
+ --hash=sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761 \
+ --hash=sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0 \
+ --hash=sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e \
+ --hash=sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af \
+ --hash=sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa \
+ --hash=sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c \
+ --hash=sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42 \
+ --hash=sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e \
+ --hash=sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81 \
+ --hash=sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e \
+ --hash=sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617 \
+ --hash=sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc \
+ --hash=sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de \
+ --hash=sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111 \
+ --hash=sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383 \
+ --hash=sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70 \
+ --hash=sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6 \
+ --hash=sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4 \
+ --hash=sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011 \
+ --hash=sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803 \
+ --hash=sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79 \
+ --hash=sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f
+ # via rubin-nublado-client
+gunicorn==23.0.0 \
+ --hash=sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d \
+ --hash=sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec
# via -r requirements/main.in
h11==0.14.0 \
--hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \
@@ -149,592 +337,779 @@ h11==0.14.0 \
# via
# httpcore
# uvicorn
-hiredis==2.3.2 \
- --hash=sha256:01b6c24c0840ac7afafbc4db236fd55f56a9a0919a215c25a238f051781f4772 \
- --hash=sha256:02fc71c8333586871602db4774d3a3e403b4ccf6446dc4603ec12df563127cee \
- --hash=sha256:0c0773266e1c38a06e7593bd08870ac1503f5f0ce0f5c63f2b4134b090b5d6a4 \
- --hash=sha256:0c5f6972d2bdee3cd301d5c5438e31195cf1cabf6fd9274491674d4ceb46914d \
- --hash=sha256:0da56915bda1e0a49157191b54d3e27689b70960f0685fdd5c415dacdee2fbed \
- --hash=sha256:14c7b43205e515f538a9defb4e411e0f0576caaeeda76bb9993ed505486f7562 \
- --hash=sha256:16b01d9ceae265d4ab9547be0cd628ecaff14b3360357a9d30c029e5ae8b7e7f \
- --hash=sha256:1979334ccab21a49c544cd1b8d784ffb2747f99a51cb0bd0976eebb517628382 \
- --hash=sha256:1c4c0bcf786f0eac9593367b6279e9b89534e008edbf116dcd0de956524702c8 \
- --hash=sha256:1d63318ca189fddc7e75f6a4af8eae9c0545863619fb38cfba5f43e81280b286 \
- --hash=sha256:27e9619847e9dc70b14b1ad2d0fb4889e7ca18996585c3463cff6c951fd6b10b \
- --hash=sha256:28adecb308293e705e44087a1c2d557a816f032430d8a2a9bb7873902a1c6d48 \
- --hash=sha256:28bd184b33e0dd6d65816c16521a4ba1ffbe9ff07d66873c42ea4049a62fed83 \
- --hash=sha256:322c668ee1c12d6c5750a4b1057e6b4feee2a75b3d25d630922a463cfe5e7478 \
- --hash=sha256:333b5e04866758b11bda5f5315b4e671d15755fc6ed3b7969721bc6311d0ee36 \
- --hash=sha256:33d5ebc93c39aed4b5bc769f8ce0819bc50e74bb95d57a35f838f1c4378978e0 \
- --hash=sha256:380e029bb4b1d34cf560fcc8950bf6b57c2ef0c9c8b7c7ac20b7c524a730fadd \
- --hash=sha256:387f655444d912a963ab68abf64bf6e178a13c8e4aa945cb27388fd01a02e6f1 \
- --hash=sha256:3dd63d0bbbe75797b743f35d37a4cca7ca7ba35423a0de742ae2985752f20c6d \
- --hash=sha256:419780f8583ddb544ffa86f9d44a7fcc183cd826101af4e5ffe535b6765f5f6b \
- --hash=sha256:4852f4bf88f0e2d9bdf91279892f5740ed22ae368335a37a52b92a5c88691140 \
- --hash=sha256:49532d7939cc51f8e99efc326090c54acf5437ed88b9c904cc8015b3c4eda9c9 \
- --hash=sha256:4baf4b579b108062e91bd2a991dc98b9dc3dc06e6288db2d98895eea8acbac22 \
- --hash=sha256:4d59f88c4daa36b8c38e59ac7bffed6f5d7f68eaccad471484bf587b28ccc478 \
- --hash=sha256:4fc242e9da4af48714199216eb535b61e8f8d66552c8819e33fc7806bd465a09 \
- --hash=sha256:532a84a82156a82529ec401d1c25d677c6543c791e54a263aa139541c363995f \
- --hash=sha256:5341ce3d01ef3c7418a72e370bf028c7aeb16895e79e115fe4c954fff990489e \
- --hash=sha256:53d0f2c59bce399b8010a21bc779b4f8c32d0f582b2284ac8c98dc7578b27bc4 \
- --hash=sha256:55ce31bf4711da879b96d511208efb65a6165da4ba91cb3a96d86d5a8d9d23e6 \
- --hash=sha256:56e9b7d6051688ca94e68c0c8a54a243f8db841911b683cedf89a29d4de91509 \
- --hash=sha256:57c0d0c7e308ed5280a4900d4468bbfec51f0e1b4cde1deae7d4e639bc6b7766 \
- --hash=sha256:5986fb5f380169270a0293bebebd95466a1c85010b4f1afc2727e4d17c452512 \
- --hash=sha256:5bd42d0d45ea47a2f96babd82a659fbc60612ab9423a68e4a8191e538b85542a \
- --hash=sha256:5c614552c6bd1d0d907f448f75550f6b24fb56cbfce80c094908b7990cad9702 \
- --hash=sha256:63a090761ddc3c1f7db5e67aa4e247b4b3bb9890080bdcdadd1b5200b8b89ac4 \
- --hash=sha256:63b99b5ea9fe4f21469fb06a16ca5244307678636f11917359e3223aaeca0b67 \
- --hash=sha256:66ab949424ac6504d823cba45c4c4854af5c59306a1531edb43b4dd22e17c102 \
- --hash=sha256:684840b014ce83541a087fcf2d48227196576f56ae3e944d4dfe14c0a3e0ccb7 \
- --hash=sha256:6871306d8b98a15e53a5f289ec1106a3a1d43e7ab6f4d785f95fcef9a7bd9504 \
- --hash=sha256:6b4edee59dc089bc3948f4f6fba309f51aa2ccce63902364900aa0a553a85e97 \
- --hash=sha256:6d7302b4b17fcc1cc727ce84ded7f6be4655701e8d58744f73b09cb9ed2b13df \
- --hash=sha256:6dbfe1887ffa5cf3030451a56a8f965a9da2fa82b7149357752b67a335a05fc6 \
- --hash=sha256:70d226ab0306a5b8d408235cabe51d4bf3554c9e8a72d53ce0b3c5c84cf78881 \
- --hash=sha256:7298562a49d95570ab1c7fc4051e72824c6a80e907993a21a41ba204223e7334 \
- --hash=sha256:733e2456b68f3f126ddaf2cd500a33b25146c3676b97ea843665717bda0c5d43 \
- --hash=sha256:742093f33d374098aa21c1696ac6e4874b52658c870513a297a89265a4d08fe5 \
- --hash=sha256:7bac7e02915b970c3723a7a7c5df4ba7a11a3426d2a3f181e041aa506a1ff028 \
- --hash=sha256:7e8bf4444b09419b77ce671088db9f875b26720b5872d97778e2545cd87dba4a \
- --hash=sha256:7f39f28ffc65de577c3bc0c7615f149e35bc927802a0f56e612db9b530f316f9 \
- --hash=sha256:80441b55edbef868e2563842f5030982b04349408396e5ac2b32025fb06b5212 \
- --hash=sha256:80b02d27864ebaf9b153d4b99015342382eeaed651f5591ce6f07e840307c56d \
- --hash=sha256:88cb0b35b63717ef1e41d62f4f8717166f7c6245064957907cfe177cc144357c \
- --hash=sha256:8c490191fa1218851f8a80c5a21a05a6f680ac5aebc2e688b71cbfe592f8fec6 \
- --hash=sha256:8e3f8b1733078ac663dad57e20060e16389a60ab542f18a97931f3a2a2dd64a4 \
- --hash=sha256:8f34801b251ca43ad70691fb08b606a2e55f06b9c9fb1fc18fd9402b19d70f7b \
- --hash=sha256:8fc7197ff33047ce43a67851ccf190acb5b05c52fd4a001bb55766358f04da68 \
- --hash=sha256:92830c16885f29163e1c2da1f3c1edb226df1210ec7e8711aaabba3dd0d5470a \
- --hash=sha256:9412a06b8a8e09abd6313d96864b6d7713c6003a365995a5c70cfb9209df1570 \
- --hash=sha256:948d9f2ca7841794dd9b204644963a4bcd69ced4e959b0d4ecf1b8ce994a6daa \
- --hash=sha256:9a0026cfbf29f07649b0e34509091a2a6016ff8844b127de150efce1c3aff60b \
- --hash=sha256:9c431431abf55b64347ddc8df68b3ef840269cb0aa5bc2d26ad9506eb4b1b866 \
- --hash=sha256:9e14fb70ca4f7efa924f508975199353bf653f452e4ef0a1e47549e208f943d7 \
- --hash=sha256:a45857e87e9d2b005e81ddac9d815a33efd26ec67032c366629f023fe64fb415 \
- --hash=sha256:a50c8af811b35b8a43b1590cf890b61ff2233225257a3cad32f43b3ec7ff1b9f \
- --hash=sha256:a6481c3b7673a86276220140456c2a6fbfe8d1fb5c613b4728293c8634134824 \
- --hash=sha256:a6b54dabfaa5dbaa92f796f0c32819b4636e66aa8e9106c3d421624bd2a2d676 \
- --hash=sha256:a797d8c7df9944314d309b0d9e1b354e2fa4430a05bb7604da13b6ad291bf959 \
- --hash=sha256:a91a14dd95e24dc078204b18b0199226ee44644974c645dc54ee7b00c3157330 \
- --hash=sha256:adfbf2e9c38b77d0db2fb32c3bdaea638fa76b4e75847283cd707521ad2475ef \
- --hash=sha256:ba3dc0af0def8c21ce7d903c59ea1e8ec4cb073f25ece9edaec7f92a286cd219 \
- --hash=sha256:bb777a38797c8c7df0444533119570be18d1a4ce5478dffc00c875684df7bfcb \
- --hash=sha256:bcbe47da0aebc00a7cfe3ebdcff0373b86ce2b1856251c003e3d69c9db44b5a7 \
- --hash=sha256:bd1cee053416183adcc8e6134704c46c60c3f66b8faaf9e65bf76191ca59a2f7 \
- --hash=sha256:bd40d2e2f82a483de0d0a6dfd8c3895a02e55e5c9949610ecbded18188fd0a56 \
- --hash=sha256:bfa73e3f163c6e8b2ec26f22285d717a5f77ab2120c97a2605d8f48b26950dac \
- --hash=sha256:c1f567489f422d40c21e53212a73bef4638d9f21043848150f8544ef1f3a6ad1 \
- --hash=sha256:c3dde4ca00fe9eee3b76209711f1941bb86db42b8a75d7f2249ff9dfc026ab0e \
- --hash=sha256:c8937f1100435698c18e4da086968c4b5d70e86ea718376f833475ab3277c9aa \
- --hash=sha256:ca33c175c1cf60222d9c6d01c38fc17ec3a484f32294af781de30226b003e00f \
- --hash=sha256:ce42649e2676ad783186264d5ffc788a7612ecd7f9effb62d51c30d413a3eefe \
- --hash=sha256:cfa67afe2269b2d203cd1389c00c5bc35a287cd57860441fb0e53b371ea6a029 \
- --hash=sha256:d47c915897a99d0d34a39fad4be97b4b709ab3d0d3b779ebccf2b6024a8c681e \
- --hash=sha256:d4dd676107a1d3c724a56a9d9db38166ad4cf44f924ee701414751bd18a784a0 \
- --hash=sha256:d711c107e83117129b7f8bd08e9820c43ceec6204fff072a001fd82f6d13db9f \
- --hash=sha256:dc1c3fd49930494a67dcec37d0558d99d84eca8eb3f03b17198424538f2608d7 \
- --hash=sha256:de3a32b4b76d46f1eb42b24a918d51d8ca52411a381748196241d59a895f7c5c \
- --hash=sha256:dfa904045d7cebfb0f01dad51352551cce1d873d7c3f80c7ded7d42f8cac8f89 \
- --hash=sha256:e138d141ec5a6ec800b6d01ddc3e5561ce1c940215e0eb9960876bfde7186aae \
- --hash=sha256:e15a408f71a6c8c87b364f1f15a6cd9c1baca12bbc47a326ac8ab99ec7ad3c64 \
- --hash=sha256:e1d86b75de787481b04d112067a4033e1ecfda2a060e50318a74e4e1c9b2948c \
- --hash=sha256:e2674a5a3168349435b08fa0b82998ed2536eb9acccf7087efe26e4cd088a525 \
- --hash=sha256:e58494f282215fc461b06709e9a195a24c12ba09570f25bdf9efb036acc05101 \
- --hash=sha256:e627d8ef5e100556e09fb44c9571a432b10e11596d3c4043500080ca9944a91a \
- --hash=sha256:e741ffe4e2db78a1b9dd6e5d29678ce37fbaaf65dfe132e5b82a794413302ef1 \
- --hash=sha256:e81aa4e9a1fcf604c8c4b51aa5d258e195a6ba81efe1da82dea3204443eba01c \
- --hash=sha256:e96cd35df012a17c87ae276196ea8f215e77d6eeca90709eb03999e2d5e3fd8a \
- --hash=sha256:ea002656a8d974daaf6089863ab0a306962c8b715db6b10879f98b781a2a5bf5 \
- --hash=sha256:eae62ed60d53b3561148bcd8c2383e430af38c0deab9f2dd15f8874888ffd26f \
- --hash=sha256:eb8797b528c1ff81eef06713623562b36db3dafa106b59f83a6468df788ff0d1 \
- --hash=sha256:eb98038ccd368e0d88bd92ee575c58cfaf33e77f788c36b2a89a84ee1936dc6b \
- --hash=sha256:ec444ab8f27562a363672d6a7372bc0700a1bdc9764563c57c5f9efa0e592b5f \
- --hash=sha256:ed63e8b75c193c5e5a8288d9d7b011da076cc314fafc3bfd59ec1d8a750d48c8 \
- --hash=sha256:f2c9c0d910dd3f7df92f0638e7f65d8edd7f442203caf89c62fc79f11b0b73f8 \
- --hash=sha256:f3020b60e3fc96d08c2a9b011f1c2e2a6bdcc09cb55df93c509b88be5cb791df \
- --hash=sha256:f47775e27388b58ce52f4f972f80e45b13c65113e9e6b6bf60148f893871dc9b \
- --hash=sha256:f70481213373d44614148f0f2e38e7905be3f021902ae5167289413196de4ba4 \
- --hash=sha256:f9de7586522e5da6bee83c9cf0dcccac0857a43249cb4d721a2e312d98a684d1 \
- --hash=sha256:f9f606e810858207d4b4287b4ef0dc622c2aa469548bf02b59dcc616f134f811 \
- --hash=sha256:fa45f7d771094b8145af10db74704ab0f698adb682fbf3721d8090f90e42cc49
+hiredis==3.0.0 \
+ --hash=sha256:00018f22f38530768b73ea86c11f47e8d4df65facd4e562bd78773bd1baef35e \
+ --hash=sha256:034925b5fb514f7b11aac38cd55b3fd7e9d3af23bd6497f3f20aa5b8ba58e232 \
+ --hash=sha256:038756db735e417ab36ee6fd7725ce412385ed2bd0767e8179a4755ea11b804f \
+ --hash=sha256:04ccae6dcd9647eae6025425ab64edb4d79fde8b9e6e115ebfabc6830170e3b2 \
+ --hash=sha256:0aacc0a78e1d94d843a6d191f224a35893e6bdfeb77a4a89264155015c65f126 \
+ --hash=sha256:0bb6f9fd92f147ba11d338ef5c68af4fd2908739c09e51f186e1d90958c68cc1 \
+ --hash=sha256:0dcfa684966f25b335072115de2f920228a3c2caf79d4bfa2b30f6e4f674a948 \
+ --hash=sha256:100431e04d25a522ef2c3b94f294c4219c4de3bfc7d557b6253296145a144c11 \
+ --hash=sha256:120f2dda469b28d12ccff7c2230225162e174657b49cf4cd119db525414ae281 \
+ --hash=sha256:122171ff47d96ed8dd4bba6c0e41d8afaba3e8194949f7720431a62aa29d8895 \
+ --hash=sha256:13c275b483a052dd645eb2cb60d6380f1f5215e4c22d6207e17b86be6dd87ffa \
+ --hash=sha256:13c345e7278c210317e77e1934b27b61394fee0dec2e8bd47e71570900f75823 \
+ --hash=sha256:1f669212c390eebfbe03c4e20181f5970b82c5d0a0ad1df1785f7ffbe7d61150 \
+ --hash=sha256:1fb8de899f0145d6c4d5d4bd0ee88a78eb980a7ffabd51e9889251b8f58f1785 \
+ --hash=sha256:204b79b30a0e6be0dc2301a4d385bb61472809f09c49f400497f1cdd5a165c66 \
+ --hash=sha256:22c17c96143c2a62dfd61b13803bc5de2ac526b8768d2141c018b965d0333b66 \
+ --hash=sha256:23142a8af92a13fc1e3f2ca1d940df3dcf2af1d176be41fe8d89e30a837a0b60 \
+ --hash=sha256:3d22c53f0ec5c18ecb3d92aa9420563b1c5d657d53f01356114978107b00b860 \
+ --hash=sha256:3dc8043959b50141df58ab4f398e8ae84c6f9e673a2c9407be65fc789138f4a6 \
+ --hash=sha256:3ea635101b739c12effd189cc19b2671c268abb03013fd1f6321ca29df3ca625 \
+ --hash=sha256:41afc0d3c18b59eb50970479a9c0e5544fb4b95e3a79cf2fbaece6ddefb926fe \
+ --hash=sha256:4664dedcd5933364756d7251a7ea86d60246ccf73a2e00912872dacbfcef8978 \
+ --hash=sha256:466f836dbcf86de3f9692097a7a01533dc9926986022c6617dc364a402b265c5 \
+ --hash=sha256:467d28112c7faa29b7db743f40803d927c8591e9da02b6ce3d5fadc170a542a2 \
+ --hash=sha256:47de0bbccf4c8a9f99d82d225f7672b9dd690d8fd872007b933ef51a302c9fa6 \
+ --hash=sha256:484025d2eb8f6348f7876fc5a2ee742f568915039fcb31b478fd5c242bb0fe3a \
+ --hash=sha256:48727d7d405d03977d01885f317328dc21d639096308de126c2c4e9950cbd3c9 \
+ --hash=sha256:4b182791c41c5eb1d9ed736f0ff81694b06937ca14b0d4dadde5dadba7ff6dae \
+ --hash=sha256:4c6efcbb5687cf8d2aedcc2c3ed4ac6feae90b8547427d417111194873b66b06 \
+ --hash=sha256:4ea3a86405baa8eb0d3639ced6926ad03e07113de54cb00fd7510cb0db76a89d \
+ --hash=sha256:50a196af0ce657fcde9bf8a0bbe1032e22c64d8fcec2bc926a35e7ff68b3a166 \
+ --hash=sha256:50da7a9edf371441dfcc56288d790985ee9840d982750580710a9789b8f4a290 \
+ --hash=sha256:51b99cfac514173d7b8abdfe10338193e8a0eccdfe1870b646009d2fb7cbe4b5 \
+ --hash=sha256:54a6dd7b478e6eb01ce15b3bb5bf771e108c6c148315bf194eb2ab776a3cac4d \
+ --hash=sha256:562eaf820de045eb487afaa37e6293fe7eceb5b25e158b5a1974b7e40bf04543 \
+ --hash=sha256:5a8dffb5f5b3415a4669d25de48b617fd9d44b0bccfc4c2ab24b06406ecc9ecb \
+ --hash=sha256:5b5cff42a522a0d81c2ae7eae5e56d0ee7365e0c4ad50c4de467d8957aff4414 \
+ --hash=sha256:63482db3fadebadc1d01ad33afa6045ebe2ea528eb77ccaabd33ee7d9c2bad48 \
+ --hash=sha256:6ca41fa40fa019cde42c21add74aadd775e71458051a15a352eabeb12eb4d084 \
+ --hash=sha256:6eecb343c70629f5af55a8b3e53264e44fa04e155ef7989de13668a0cb102a90 \
+ --hash=sha256:719c32147ba29528cb451f037bf837dcdda4ff3ddb6cdb12c4216b0973174718 \
+ --hash=sha256:77c8006c12154c37691b24ff293c077300c22944018c3ff70094a33e10c1d795 \
+ --hash=sha256:793c80a3d6b0b0e8196a2d5de37a08330125668c8012922685e17aa9108c33ac \
+ --hash=sha256:7d99b91e42217d7b4b63354b15b41ce960e27d216783e04c4a350224d55842a4 \
+ --hash=sha256:82f794d564f4bc76b80c50b03267fe5d6589e93f08e66b7a2f674faa2fa76ebc \
+ --hash=sha256:83a29cc7b21b746cb6a480189e49f49b2072812c445e66a9e38d2004d496b81c \
+ --hash=sha256:869f6d5537d243080f44253491bb30aa1ec3c21754003b3bddeadedeb65842b0 \
+ --hash=sha256:8854969e7480e8d61ed7549eb232d95082a743e94138d98d7222ba4e9f7ecacd \
+ --hash=sha256:898636a06d9bf575d2c594129085ad6b713414038276a4bfc5db7646b8a5be78 \
+ --hash=sha256:8e0bb6102ebe2efecf8a3292c6660a0e6fac98176af6de67f020bea1c2343717 \
+ --hash=sha256:8fed69bbaa307040c62195a269f82fc3edf46b510a17abb6b30a15d7dab548df \
+ --hash=sha256:9862db92ef67a8a02e0d5370f07d380e14577ecb281b79720e0d7a89aedb9ee5 \
+ --hash=sha256:98a152052b8878e5e43a2e3a14075218adafc759547c98668a21e9485882696c \
+ --hash=sha256:99516d99316062824a24d145d694f5b0d030c80da693ea6f8c4ecf71a251d8bb \
+ --hash=sha256:9b285ef6bf1581310b0d5e8f6ce64f790a1c40e89c660e1320b35f7515433672 \
+ --hash=sha256:a131377493a59fb0f5eaeb2afd49c6540cafcfba5b0b3752bed707be9e7c4eaf \
+ --hash=sha256:a1c81c89ed765198da27412aa21478f30d54ef69bf5e4480089d9c3f77b8f882 \
+ --hash=sha256:a2537b2cd98192323fce4244c8edbf11f3cac548a9d633dbbb12b48702f379f4 \
+ --hash=sha256:a41be8af1fd78ca97bc948d789a09b730d1e7587d07ca53af05758f31f4b985d \
+ --hash=sha256:a631e2990b8be23178f655cae8ac6c7422af478c420dd54e25f2e26c29e766f1 \
+ --hash=sha256:a6a49ef161739f8018c69b371528bdb47d7342edfdee9ddc75a4d8caddf45a6e \
+ --hash=sha256:ac6d929cb33dd12ad3424b75725975f0a54b5b12dbff95f2a2d660c510aa106d \
+ --hash=sha256:b23291951959141173eec10f8573538e9349fa27f47a0c34323d1970bf891ee5 \
+ --hash=sha256:ba9fc605ac558f0de67463fb588722878641e6fa1dabcda979e8e69ff581d0bd \
+ --hash=sha256:bdc144d56333c52c853c31b4e2e52cfbdb22d3da4374c00f5f3d67c42158970f \
+ --hash=sha256:c073848d2b1d5561f3903879ccf4e1a70c9b1e7566c7bdcc98d082fa3e7f0a1d \
+ --hash=sha256:c1018cc7f12824506f165027eabb302735b49e63af73eb4d5450c66c88f47026 \
+ --hash=sha256:c3ece960008dab66c6b8bb3a1350764677ee7c74ccd6270aaf1b1caf9ccebb46 \
+ --hash=sha256:c3fdad75e7837a475900a1d3a5cc09aa024293c3b0605155da2d42f41bc0e482 \
+ --hash=sha256:c8a1df39d74ec507d79c7a82c8063eee60bf80537cdeee652f576059b9cdd15c \
+ --hash=sha256:c8a91e9520fbc65a799943e5c970ffbcd67905744d8becf2e75f9f0a5e8414f0 \
+ --hash=sha256:d10fcd9e0eeab835f492832b2a6edb5940e2f1230155f33006a8dfd3bd2c94e4 \
+ --hash=sha256:d435ae89073d7cd51e6b6bf78369c412216261c9c01662e7008ff00978153729 \
+ --hash=sha256:d7a4c1791d7aa7e192f60fe028ae409f18ccdd540f8b1e6aeb0df7816c77e4a4 \
+ --hash=sha256:dc384874a719c767b50a30750f937af18842ee5e288afba95a5a3ed703b1515a \
+ --hash=sha256:df274e3abb4df40f4c7274dd3e587dfbb25691826c948bc98d5fead019dfb001 \
+ --hash=sha256:e069967cbd5e1900aafc4b5943888f6d34937fc59bf8918a1a546cb729b4b1e4 \
+ --hash=sha256:e194a0d5df9456995d8f510eab9f529213e7326af6b94770abf8f8b7952ddcaa \
+ --hash=sha256:e1a9c14ae9573d172dc050a6f63a644457df5d01ec4d35a6a0f097f812930f83 \
+ --hash=sha256:e241fab6332e8fb5f14af00a4a9c6aefa22f19a336c069b7ddbf28ef8341e8d6 \
+ --hash=sha256:e421ac9e4b5efc11705a0d5149e641d4defdc07077f748667f359e60dc904420 \
+ --hash=sha256:e43679eca508ba8240d016d8cca9d27342d70184773c15bea78a23c87a1922f1 \
+ --hash=sha256:e584fe5f4e6681d8762982be055f1534e0170f6308a7a90f58d737bab12ff6a8 \
+ --hash=sha256:f114a6c86edbf17554672b050cce72abf489fe58d583c7921904d5f1c9691605 \
+ --hash=sha256:f2f312eef8aafc2255e3585dcf94d5da116c43ef837db91db9ecdc1bc930072d \
+ --hash=sha256:f359175197fd833c8dd7a8c288f1516be45415bb5c939862ab60c2918e1e1943 \
+ --hash=sha256:f75999ae00a920f7dce6ecae76fa5e8674a3110e5a75f12c7a2c75ae1af53396 \
+ --hash=sha256:f91456507427ba36fd81b2ca11053a8e112c775325acc74e993201ea912d63e9 \
+ --hash=sha256:fa1fcad89d8a41d8dc10b1e54951ec1e161deabd84ed5a2c95c3c7213bdb3514 \
+ --hash=sha256:fa86bf9a0ed339ec9e8a9a9d0ae4dccd8671625c83f9f9f2640729b15e07fbfd \
+ --hash=sha256:fcdb552ffd97151dab8e7bc3ab556dfa1512556b48a367db94b5c20253a35ee1 \
+ --hash=sha256:fcecbd39bd42cef905c0b51c9689c39d0cc8b88b1671e7f40d4fb213423aef3a \
+ --hash=sha256:fe91d62b0594db5ea7d23fc2192182b1a7b6973f628a9b8b2e0a42a2be721ac6 \
+ --hash=sha256:fed8581ae26345dea1f1e0d1a96e05041a727a45e7d8d459164583e23c6ac441
# via
# aioredis
# redis
-httpcore==1.0.2 \
- --hash=sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7 \
- --hash=sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535
+httpcore==1.0.6 \
+ --hash=sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f \
+ --hash=sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f
# via httpx
-httptools==0.6.1 \
- --hash=sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563 \
- --hash=sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142 \
- --hash=sha256:0cf2372e98406efb42e93bfe10f2948e467edfd792b015f1b4ecd897903d3e8d \
- --hash=sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b \
- --hash=sha256:3c3b214ce057c54675b00108ac42bacf2ab8f85c58e3f324a4e963bbc46424f4 \
- --hash=sha256:3e802e0b2378ade99cd666b5bffb8b2a7cc8f3d28988685dc300469ea8dd86cb \
- --hash=sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658 \
- --hash=sha256:405784577ba6540fa7d6ff49e37daf104e04f4b4ff2d1ac0469eaa6a20fde084 \
- --hash=sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2 \
- --hash=sha256:4bd3e488b447046e386a30f07af05f9b38d3d368d1f7b4d8f7e10af85393db97 \
- --hash=sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837 \
- --hash=sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3 \
- --hash=sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58 \
- --hash=sha256:678fcbae74477a17d103b7cae78b74800d795d702083867ce160fc202104d0da \
- --hash=sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d \
- --hash=sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90 \
- --hash=sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0 \
- --hash=sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1 \
- --hash=sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2 \
- --hash=sha256:7ebaec1bf683e4bf5e9fbb49b8cc36da482033596a415b3e4ebab5a4c0d7ec5e \
- --hash=sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0 \
- --hash=sha256:8ae5b97f690badd2ca27cbf668494ee1b6d34cf1c464271ef7bfa9ca6b83ffaf \
- --hash=sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc \
- --hash=sha256:8e216a038d2d52ea13fdd9b9c9c7459fb80d78302b257828285eca1c773b99b3 \
- --hash=sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503 \
- --hash=sha256:95658c342529bba4e1d3d2b1a874db16c7cca435e8827422154c9da76ac4e13a \
- --hash=sha256:95fb92dd3649f9cb139e9c56604cc2d7c7bf0fc2e7c8d7fbd58f96e35eddd2a3 \
- --hash=sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949 \
- --hash=sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84 \
- --hash=sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb \
- --hash=sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a \
- --hash=sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f \
- --hash=sha256:dcbab042cc3ef272adc11220517278519adf8f53fd3056d0e68f0a6f891ba94e \
- --hash=sha256:e0b281cf5a125c35f7f6722b65d8542d2e57331be573e9e88bc8b0115c4a7a81 \
- --hash=sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185 \
- --hash=sha256:fe467eb086d80217b7584e61313ebadc8d187a4d95bb62031b7bab4b205c3ba3
+httptools==0.6.4 \
+ --hash=sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a \
+ --hash=sha256:0e563e54979e97b6d13f1bbc05a96109923e76b901f786a5eae36e99c01237bd \
+ --hash=sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2 \
+ --hash=sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17 \
+ --hash=sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8 \
+ --hash=sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3 \
+ --hash=sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5 \
+ --hash=sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da \
+ --hash=sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0 \
+ --hash=sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721 \
+ --hash=sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636 \
+ --hash=sha256:40dc6a8e399e15ea525305a2ddba998b0af5caa2566bcd79dcbe8948181eeaff \
+ --hash=sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0 \
+ --hash=sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071 \
+ --hash=sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c \
+ --hash=sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4 \
+ --hash=sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1 \
+ --hash=sha256:703c346571fa50d2e9856a37d7cd9435a25e7fd15e236c397bf224afaa355fe9 \
+ --hash=sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44 \
+ --hash=sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083 \
+ --hash=sha256:85797e37e8eeaa5439d33e556662cc370e474445d5fab24dcadc65a8ffb04003 \
+ --hash=sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959 \
+ --hash=sha256:94978a49b8f4569ad607cd4946b759d90b285e39c0d4640c6b36ca7a3ddf2efc \
+ --hash=sha256:aafe0f1918ed07b67c1e838f950b1c1fabc683030477e60b335649b8020e1076 \
+ --hash=sha256:ab9ba8dcf59de5181f6be44a77458e45a578fc99c31510b8c65b7d5acc3cf490 \
+ --hash=sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660 \
+ --hash=sha256:b799de31416ecc589ad79dd85a0b2657a8fe39327944998dea368c1d4c9e55e6 \
+ --hash=sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c \
+ --hash=sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50 \
+ --hash=sha256:d1ffd262a73d7c28424252381a5b854c19d9de5f56f075445d33919a637e3547 \
+ --hash=sha256:d3f0d369e7ffbe59c4b6116a44d6a8eb4783aae027f2c0b366cf0aa964185dba \
+ --hash=sha256:d54efd20338ac52ba31e7da78e4a72570cf729fac82bc31ff9199bedf1dc7440 \
+ --hash=sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988 \
+ --hash=sha256:db353d22843cf1028f43c3651581e4bb49374d85692a85f95f7b9a130e1b2cab \
+ --hash=sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970 \
+ --hash=sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1 \
+ --hash=sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2 \
+ --hash=sha256:df959752a0c2748a65ab5387d08287abf6779ae9165916fe053e68ae1fbdc47f \
+ --hash=sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81 \
+ --hash=sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069 \
+ --hash=sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975 \
+ --hash=sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f \
+ --hash=sha256:fc411e1c0a7dcd2f902c7c48cf079947a7e65b5485dea9decb82b9105ca71a43
# via uvicorn
-httpx==0.26.0 \
- --hash=sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf \
- --hash=sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd
+httpx==0.27.2 \
+ --hash=sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0 \
+ --hash=sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2
# via
# -r requirements/main.in
+ # python-schema-registry-client
+ # rubin-nublado-client
# safir
-idna==3.6 \
- --hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \
- --hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
+httpx-sse==0.4.0 \
+ --hash=sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721 \
+ --hash=sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f
+ # via rubin-nublado-client
+humanize==4.11.0 \
+ --hash=sha256:b53caaec8532bcb2fff70c8826f904c35943f8cecaca29d272d9df38092736c0 \
+ --hash=sha256:e66f36020a2d5a974c504bd2555cf770621dbdbb6d82f94a6857c0b1ea2608be
+ # via -r requirements/main.in
+idna==3.10 \
+ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \
+ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
# via
# anyio
# httpx
-packaging==23.2 \
- --hash=sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5 \
- --hash=sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7
- # via gunicorn
-pycparser==2.21 \
- --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \
- --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206
+inflection==0.5.1 \
+ --hash=sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417 \
+ --hash=sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2
+ # via dataclasses-avroschema
+jsonschema==4.23.0 \
+ --hash=sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4 \
+ --hash=sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566
+ # via python-schema-registry-client
+jsonschema-specifications==2024.10.1 \
+ --hash=sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272 \
+ --hash=sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf
+ # via jsonschema
+packaging==24.1 \
+ --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \
+ --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124
+ # via
+ # aiokafka
+ # gunicorn
+pycparser==2.22 \
+ --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
+ --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
# via cffi
-pydantic==2.5.3 \
- --hash=sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a \
- --hash=sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4
+pydantic==2.9.2 \
+ --hash=sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f \
+ --hash=sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12
# via
# -r requirements/main.in
+ # fast-depends
# fastapi
# pydantic-settings
+ # rubin-nublado-client
# safir
-pydantic-core==2.14.6 \
- --hash=sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556 \
- --hash=sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e \
- --hash=sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411 \
- --hash=sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245 \
- --hash=sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c \
- --hash=sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66 \
- --hash=sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd \
- --hash=sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d \
- --hash=sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b \
- --hash=sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06 \
- --hash=sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948 \
- --hash=sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341 \
- --hash=sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0 \
- --hash=sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f \
- --hash=sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a \
- --hash=sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2 \
- --hash=sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51 \
- --hash=sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80 \
- --hash=sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8 \
- --hash=sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d \
- --hash=sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8 \
- --hash=sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb \
- --hash=sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590 \
- --hash=sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87 \
- --hash=sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534 \
- --hash=sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b \
- --hash=sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145 \
- --hash=sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba \
- --hash=sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b \
- --hash=sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2 \
- --hash=sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e \
- --hash=sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052 \
- --hash=sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622 \
- --hash=sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab \
- --hash=sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b \
- --hash=sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66 \
- --hash=sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e \
- --hash=sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4 \
- --hash=sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e \
- --hash=sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec \
- --hash=sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c \
- --hash=sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed \
- --hash=sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937 \
- --hash=sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f \
- --hash=sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9 \
- --hash=sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4 \
- --hash=sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96 \
- --hash=sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277 \
- --hash=sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23 \
- --hash=sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7 \
- --hash=sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b \
- --hash=sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91 \
- --hash=sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d \
- --hash=sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e \
- --hash=sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1 \
- --hash=sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2 \
- --hash=sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160 \
- --hash=sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9 \
- --hash=sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670 \
- --hash=sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7 \
- --hash=sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c \
- --hash=sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb \
- --hash=sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42 \
- --hash=sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d \
- --hash=sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8 \
- --hash=sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1 \
- --hash=sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6 \
- --hash=sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8 \
- --hash=sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf \
- --hash=sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e \
- --hash=sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a \
- --hash=sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9 \
- --hash=sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1 \
- --hash=sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40 \
- --hash=sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2 \
- --hash=sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d \
- --hash=sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f \
- --hash=sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f \
- --hash=sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af \
- --hash=sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7 \
- --hash=sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda \
- --hash=sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a \
- --hash=sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95 \
- --hash=sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0 \
- --hash=sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60 \
- --hash=sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149 \
- --hash=sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975 \
- --hash=sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4 \
- --hash=sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe \
- --hash=sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94 \
- --hash=sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03 \
- --hash=sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c \
- --hash=sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b \
- --hash=sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a \
- --hash=sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24 \
- --hash=sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391 \
- --hash=sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c \
- --hash=sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab \
- --hash=sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd \
- --hash=sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786 \
- --hash=sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08 \
- --hash=sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8 \
- --hash=sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6 \
- --hash=sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0 \
- --hash=sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421
- # via pydantic
-pydantic-settings==2.1.0 \
- --hash=sha256:26b1492e0a24755626ac5e6d715e9077ab7ad4fb5f19a8b7ed7011d52f36141c \
- --hash=sha256:7621c0cb5d90d1140d2f0ef557bdf03573aac7035948109adf2574770b77605a
- # via -r requirements/main.in
-pyjwt[crypto]==2.8.0 \
- --hash=sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de \
- --hash=sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320
+ # safir-arq
+pydantic-core==2.23.4 \
+ --hash=sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36 \
+ --hash=sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05 \
+ --hash=sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071 \
+ --hash=sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327 \
+ --hash=sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c \
+ --hash=sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36 \
+ --hash=sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29 \
+ --hash=sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744 \
+ --hash=sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d \
+ --hash=sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec \
+ --hash=sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e \
+ --hash=sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e \
+ --hash=sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577 \
+ --hash=sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232 \
+ --hash=sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863 \
+ --hash=sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6 \
+ --hash=sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368 \
+ --hash=sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480 \
+ --hash=sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2 \
+ --hash=sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2 \
+ --hash=sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6 \
+ --hash=sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769 \
+ --hash=sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d \
+ --hash=sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2 \
+ --hash=sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84 \
+ --hash=sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166 \
+ --hash=sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271 \
+ --hash=sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5 \
+ --hash=sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb \
+ --hash=sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13 \
+ --hash=sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323 \
+ --hash=sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556 \
+ --hash=sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665 \
+ --hash=sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef \
+ --hash=sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb \
+ --hash=sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119 \
+ --hash=sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126 \
+ --hash=sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510 \
+ --hash=sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b \
+ --hash=sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87 \
+ --hash=sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f \
+ --hash=sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc \
+ --hash=sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8 \
+ --hash=sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21 \
+ --hash=sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f \
+ --hash=sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6 \
+ --hash=sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658 \
+ --hash=sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b \
+ --hash=sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3 \
+ --hash=sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb \
+ --hash=sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59 \
+ --hash=sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24 \
+ --hash=sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9 \
+ --hash=sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3 \
+ --hash=sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd \
+ --hash=sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753 \
+ --hash=sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55 \
+ --hash=sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad \
+ --hash=sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a \
+ --hash=sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605 \
+ --hash=sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e \
+ --hash=sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b \
+ --hash=sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433 \
+ --hash=sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8 \
+ --hash=sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07 \
+ --hash=sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728 \
+ --hash=sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0 \
+ --hash=sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327 \
+ --hash=sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555 \
+ --hash=sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64 \
+ --hash=sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6 \
+ --hash=sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea \
+ --hash=sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b \
+ --hash=sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df \
+ --hash=sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e \
+ --hash=sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd \
+ --hash=sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068 \
+ --hash=sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3 \
+ --hash=sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040 \
+ --hash=sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12 \
+ --hash=sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916 \
+ --hash=sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f \
+ --hash=sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f \
+ --hash=sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801 \
+ --hash=sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231 \
+ --hash=sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5 \
+ --hash=sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8 \
+ --hash=sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee \
+ --hash=sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607
# via
- # gidgethub
- # pyjwt
-python-dotenv==1.0.0 \
- --hash=sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba \
- --hash=sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a
+ # pydantic
+ # safir
+ # safir-arq
+pydantic-settings==2.6.1 \
+ --hash=sha256:7fb0637c786a558d3103436278a7c4f1cfd29ba8973238a50c5bb9a55387da87 \
+ --hash=sha256:e0f92546d8a9923cb8941689abf85d6601a8c19a23e97a34b2964a2e3f813ca0
+ # via
+ # -r requirements/main.in
+ # rubin-nublado-client
+ # safir
+pyjwt==2.9.0 \
+ --hash=sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850 \
+ --hash=sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c
+ # via gidgethub
+python-dateutil==2.9.0.post0 \
+ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \
+ --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427
+ # via dataclasses-avroschema
+python-dotenv==1.0.1 \
+ --hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \
+ --hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a
# via
# pydantic-settings
# uvicorn
-pyyaml==6.0.1 \
- --hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
- --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
- --hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \
- --hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \
- --hash=sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206 \
- --hash=sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27 \
- --hash=sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595 \
- --hash=sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62 \
- --hash=sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98 \
- --hash=sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696 \
- --hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \
- --hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \
- --hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \
- --hash=sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6 \
- --hash=sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867 \
- --hash=sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47 \
- --hash=sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486 \
- --hash=sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6 \
- --hash=sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3 \
- --hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \
- --hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \
- --hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \
- --hash=sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c \
- --hash=sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735 \
- --hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \
- --hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \
- --hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
- --hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
- --hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
- --hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
- --hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
- --hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \
- --hash=sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0 \
- --hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \
- --hash=sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c \
- --hash=sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c \
- --hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \
- --hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \
- --hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \
- --hash=sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859 \
- --hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \
- --hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \
- --hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \
- --hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \
- --hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \
- --hash=sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa \
- --hash=sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c \
- --hash=sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585 \
- --hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
- --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
+python-schema-registry-client==2.6.0 \
+ --hash=sha256:a0688a9cd6e2a616a79fb46a6615c531cd5f9e2a5145f5c95932f792417731cb \
+ --hash=sha256:e5495899c2bf4fd33bc6689a2068a3423dc94875677f3fd343b6e492a7877ba0
+ # via safir
+pyyaml==6.0.2 \
+ --hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \
+ --hash=sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48 \
+ --hash=sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086 \
+ --hash=sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e \
+ --hash=sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133 \
+ --hash=sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5 \
+ --hash=sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484 \
+ --hash=sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee \
+ --hash=sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5 \
+ --hash=sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68 \
+ --hash=sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a \
+ --hash=sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf \
+ --hash=sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99 \
+ --hash=sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8 \
+ --hash=sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85 \
+ --hash=sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19 \
+ --hash=sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc \
+ --hash=sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a \
+ --hash=sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1 \
+ --hash=sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317 \
+ --hash=sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c \
+ --hash=sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631 \
+ --hash=sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d \
+ --hash=sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652 \
+ --hash=sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5 \
+ --hash=sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e \
+ --hash=sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b \
+ --hash=sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8 \
+ --hash=sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476 \
+ --hash=sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706 \
+ --hash=sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563 \
+ --hash=sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237 \
+ --hash=sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b \
+ --hash=sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083 \
+ --hash=sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180 \
+ --hash=sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425 \
+ --hash=sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e \
+ --hash=sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f \
+ --hash=sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725 \
+ --hash=sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183 \
+ --hash=sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab \
+ --hash=sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774 \
+ --hash=sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725 \
+ --hash=sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e \
+ --hash=sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5 \
+ --hash=sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d \
+ --hash=sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290 \
+ --hash=sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44 \
+ --hash=sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed \
+ --hash=sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4 \
+ --hash=sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba \
+ --hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \
+ --hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4
# via
# -r requirements/main.in
+ # rubin-nublado-client
# uvicorn
-redis[hiredis]==5.0.1 \
- --hash=sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f \
- --hash=sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f
+redis==5.2.0 \
+ --hash=sha256:0b1087665a771b1ff2e003aa5bdd354f15a70c9e25d5a7dbf9c722c16528a7b0 \
+ --hash=sha256:ae174f2bb3b1bf2b09d54bf3e51fbc1469cf6c10aa03e21141f51969801a7897
+ # via arq
+referencing==0.35.1 \
+ --hash=sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c \
+ --hash=sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de
# via
- # arq
- # redis
-safir[arq]==5.1.0 \
- --hash=sha256:0e4162b3b1fca558b037c06d7221b96996d7a55c92108e2e28e744d224c0076d \
- --hash=sha256:e04019e7e914aefc5ce1a9ca73c227eb3a84255d952bcd4cf3746e11cf7b1a15
+ # jsonschema
+ # jsonschema-specifications
+rpds-py==0.20.1 \
+ --hash=sha256:02a0629ec053fc013808a85178524e3cb63a61dbc35b22499870194a63578fb9 \
+ --hash=sha256:07924c1b938798797d60c6308fa8ad3b3f0201802f82e4a2c41bb3fafb44cc28 \
+ --hash=sha256:07f59760ef99f31422c49038964b31c4dfcfeb5d2384ebfc71058a7c9adae2d2 \
+ --hash=sha256:0a3a1e9ee9728b2c1734f65d6a1d376c6f2f6fdcc13bb007a08cc4b1ff576dc5 \
+ --hash=sha256:0a90c373ea2975519b58dece25853dbcb9779b05cc46b4819cb1917e3b3215b6 \
+ --hash=sha256:0ad56edabcdb428c2e33bbf24f255fe2b43253b7d13a2cdbf05de955217313e6 \
+ --hash=sha256:0b581f47257a9fce535c4567782a8976002d6b8afa2c39ff616edf87cbeff712 \
+ --hash=sha256:0f8f741b6292c86059ed175d80eefa80997125b7c478fb8769fd9ac8943a16c0 \
+ --hash=sha256:0fc212779bf8411667234b3cdd34d53de6c2b8b8b958e1e12cb473a5f367c338 \
+ --hash=sha256:13c56de6518e14b9bf6edde23c4c39dac5b48dcf04160ea7bce8fca8397cdf86 \
+ --hash=sha256:142c0a5124d9bd0e2976089484af5c74f47bd3298f2ed651ef54ea728d2ea42c \
+ --hash=sha256:14511a539afee6f9ab492b543060c7491c99924314977a55c98bfa2ee29ce78c \
+ --hash=sha256:15a842bb369e00295392e7ce192de9dcbf136954614124a667f9f9f17d6a216f \
+ --hash=sha256:16d4477bcb9fbbd7b5b0e4a5d9b493e42026c0bf1f06f723a9353f5153e75d30 \
+ --hash=sha256:1791ff70bc975b098fe6ecf04356a10e9e2bd7dc21fa7351c1742fdeb9b4966f \
+ --hash=sha256:19b73643c802f4eaf13d97f7855d0fb527fbc92ab7013c4ad0e13a6ae0ed23bd \
+ --hash=sha256:200a23239781f46149e6a415f1e870c5ef1e712939fe8fa63035cd053ac2638e \
+ --hash=sha256:2249280b870e6a42c0d972339e9cc22ee98730a99cd7f2f727549af80dd5a963 \
+ --hash=sha256:2b431c777c9653e569986ecf69ff4a5dba281cded16043d348bf9ba505486f36 \
+ --hash=sha256:2cc3712a4b0b76a1d45a9302dd2f53ff339614b1c29603a911318f2357b04dd2 \
+ --hash=sha256:2fbb0ffc754490aff6dabbf28064be47f0f9ca0b9755976f945214965b3ace7e \
+ --hash=sha256:32b922e13d4c0080d03e7b62991ad7f5007d9cd74e239c4b16bc85ae8b70252d \
+ --hash=sha256:36785be22066966a27348444b40389f8444671630063edfb1a2eb04318721e17 \
+ --hash=sha256:37fe0f12aebb6a0e3e17bb4cd356b1286d2d18d2e93b2d39fe647138458b4bcb \
+ --hash=sha256:3aea7eed3e55119635a74bbeb80b35e776bafccb70d97e8ff838816c124539f1 \
+ --hash=sha256:3c6afcf2338e7f374e8edc765c79fbcb4061d02b15dd5f8f314a4af2bdc7feb5 \
+ --hash=sha256:3ccb8ac2d3c71cda472b75af42818981bdacf48d2e21c36331b50b4f16930163 \
+ --hash=sha256:3d089d0b88996df627693639d123c8158cff41c0651f646cd8fd292c7da90eaf \
+ --hash=sha256:3dd645e2b0dcb0fd05bf58e2e54c13875847687d0b71941ad2e757e5d89d4356 \
+ --hash=sha256:3e310838a5801795207c66c73ea903deda321e6146d6f282e85fa7e3e4854804 \
+ --hash=sha256:42cbde7789f5c0bcd6816cb29808e36c01b960fb5d29f11e052215aa85497c93 \
+ --hash=sha256:483b29f6f7ffa6af845107d4efe2e3fa8fb2693de8657bc1849f674296ff6a5a \
+ --hash=sha256:4888e117dd41b9d34194d9e31631af70d3d526efc363085e3089ab1a62c32ed1 \
+ --hash=sha256:49fe9b04b6fa685bd39237d45fad89ba19e9163a1ccaa16611a812e682913496 \
+ --hash=sha256:4a5a844f68776a7715ecb30843b453f07ac89bad393431efbf7accca3ef599c1 \
+ --hash=sha256:4a916087371afd9648e1962e67403c53f9c49ca47b9680adbeef79da3a7811b0 \
+ --hash=sha256:4f676e21db2f8c72ff0936f895271e7a700aa1f8d31b40e4e43442ba94973899 \
+ --hash=sha256:518d2ca43c358929bf08f9079b617f1c2ca6e8848f83c1225c88caeac46e6cbc \
+ --hash=sha256:5265505b3d61a0f56618c9b941dc54dc334dc6e660f1592d112cd103d914a6db \
+ --hash=sha256:55cd1fa4ecfa6d9f14fbd97ac24803e6f73e897c738f771a9fe038f2f11ff07c \
+ --hash=sha256:58b1d5dd591973d426cbb2da5e27ba0339209832b2f3315928c9790e13f159e8 \
+ --hash=sha256:59240685e7da61fb78f65a9f07f8108e36a83317c53f7b276b4175dc44151684 \
+ --hash=sha256:5b48e790e0355865197ad0aca8cde3d8ede347831e1959e158369eb3493d2191 \
+ --hash=sha256:5d4eea0761e37485c9b81400437adb11c40e13ef513375bbd6973e34100aeb06 \
+ --hash=sha256:648386ddd1e19b4a6abab69139b002bc49ebf065b596119f8f37c38e9ecee8ff \
+ --hash=sha256:653647b8838cf83b2e7e6a0364f49af96deec64d2a6578324db58380cff82aca \
+ --hash=sha256:6740a3e8d43a32629bb9b009017ea5b9e713b7210ba48ac8d4cb6d99d86c8ee8 \
+ --hash=sha256:6889469bfdc1eddf489729b471303739bf04555bb151fe8875931f8564309afc \
+ --hash=sha256:68cb0a499f2c4a088fd2f521453e22ed3527154136a855c62e148b7883b99f9a \
+ --hash=sha256:6aa97af1558a9bef4025f8f5d8c60d712e0a3b13a2fe875511defc6ee77a1ab7 \
+ --hash=sha256:6b73c67850ca7cae0f6c56f71e356d7e9fa25958d3e18a64927c2d930859b8e4 \
+ --hash=sha256:6c8e9340ce5a52f95fa7d3b552b35c7e8f3874d74a03a8a69279fd5fca5dc751 \
+ --hash=sha256:6ca91093a4a8da4afae7fe6a222c3b53ee4eef433ebfee4d54978a103435159e \
+ --hash=sha256:754bbed1a4ca48479e9d4182a561d001bbf81543876cdded6f695ec3d465846b \
+ --hash=sha256:762703bdd2b30983c1d9e62b4c88664df4a8a4d5ec0e9253b0231171f18f6d75 \
+ --hash=sha256:78f0b6877bfce7a3d1ff150391354a410c55d3cdce386f862926a4958ad5ab7e \
+ --hash=sha256:7a07ced2b22f0cf0b55a6a510078174c31b6d8544f3bc00c2bcee52b3d613f74 \
+ --hash=sha256:7dca7081e9a0c3b6490a145593f6fe3173a94197f2cb9891183ef75e9d64c425 \
+ --hash=sha256:7e21b7031e17c6b0e445f42ccc77f79a97e2687023c5746bfb7a9e45e0921b84 \
+ --hash=sha256:7f5179583d7a6cdb981151dd349786cbc318bab54963a192692d945dd3f6435d \
+ --hash=sha256:83cba698cfb3c2c5a7c3c6bac12fe6c6a51aae69513726be6411076185a8b24a \
+ --hash=sha256:842c19a6ce894493563c3bd00d81d5100e8e57d70209e84d5491940fdb8b9e3a \
+ --hash=sha256:84b8382a90539910b53a6307f7c35697bc7e6ffb25d9c1d4e998a13e842a5e83 \
+ --hash=sha256:8ba6f89cac95c0900d932c9efb7f0fb6ca47f6687feec41abcb1bd5e2bd45535 \
+ --hash=sha256:8bbe951244a838a51289ee53a6bae3a07f26d4e179b96fc7ddd3301caf0518eb \
+ --hash=sha256:925d176a549f4832c6f69fa6026071294ab5910e82a0fe6c6228fce17b0706bd \
+ --hash=sha256:92b68b79c0da2a980b1c4197e56ac3dd0c8a149b4603747c4378914a68706979 \
+ --hash=sha256:93da1d3db08a827eda74356f9f58884adb254e59b6664f64cc04cdff2cc19b0d \
+ --hash=sha256:95f3b65d2392e1c5cec27cff08fdc0080270d5a1a4b2ea1d51d5f4a2620ff08d \
+ --hash=sha256:9c4cb04a16b0f199a8c9bf807269b2f63b7b5b11425e4a6bd44bd6961d28282c \
+ --hash=sha256:a624cc00ef2158e04188df5e3016385b9353638139a06fb77057b3498f794782 \
+ --hash=sha256:a649dfd735fff086e8a9d0503a9f0c7d01b7912a333c7ae77e1515c08c146dad \
+ --hash=sha256:a94e52537a0e0a85429eda9e49f272ada715506d3b2431f64b8a3e34eb5f3e75 \
+ --hash=sha256:aa7ac11e294304e615b43f8c441fee5d40094275ed7311f3420d805fde9b07b4 \
+ --hash=sha256:b41b6321805c472f66990c2849e152aff7bc359eb92f781e3f606609eac877ad \
+ --hash=sha256:b71b8666eeea69d6363248822078c075bac6ed135faa9216aa85f295ff009b1e \
+ --hash=sha256:b9c2fe36d1f758b28121bef29ed1dee9b7a2453e997528e7d1ac99b94892527c \
+ --hash=sha256:bb63804105143c7e24cee7db89e37cb3f3941f8e80c4379a0b355c52a52b6780 \
+ --hash=sha256:be5ef2f1fc586a7372bfc355986226484e06d1dc4f9402539872c8bb99e34b01 \
+ --hash=sha256:c142b88039b92e7e0cb2552e8967077e3179b22359e945574f5e2764c3953dcf \
+ --hash=sha256:c14937af98c4cc362a1d4374806204dd51b1e12dded1ae30645c298e5a5c4cb1 \
+ --hash=sha256:ca449520e7484534a2a44faf629362cae62b660601432d04c482283c47eaebab \
+ --hash=sha256:cd945871335a639275eee904caef90041568ce3b42f402c6959b460d25ae8732 \
+ --hash=sha256:d0b937b2a1988f184a3e9e577adaa8aede21ec0b38320d6009e02bd026db04fa \
+ --hash=sha256:d126b52e4a473d40232ec2052a8b232270ed1f8c9571aaf33f73a14cc298c24f \
+ --hash=sha256:d8761c3c891cc51e90bc9926d6d2f59b27beaf86c74622c8979380a29cc23ac3 \
+ --hash=sha256:d9ecb51120de61e4604650666d1f2b68444d46ae18fd492245a08f53ad2b7711 \
+ --hash=sha256:da584ff96ec95e97925174eb8237e32f626e7a1a97888cdd27ee2f1f24dd0ad8 \
+ --hash=sha256:dbcf360c9e3399b056a238523146ea77eeb2a596ce263b8814c900263e46031a \
+ --hash=sha256:dbddc10776ca7ebf2a299c41a4dde8ea0d8e3547bfd731cb87af2e8f5bf8962d \
+ --hash=sha256:dc73505153798c6f74854aba69cc75953888cf9866465196889c7cdd351e720c \
+ --hash=sha256:e13de156137b7095442b288e72f33503a469aa1980ed856b43c353ac86390519 \
+ --hash=sha256:e1791c4aabd117653530dccd24108fa03cc6baf21f58b950d0a73c3b3b29a350 \
+ --hash=sha256:e75ba609dba23f2c95b776efb9dd3f0b78a76a151e96f96cc5b6b1b0004de66f \
+ --hash=sha256:e79059d67bea28b53d255c1437b25391653263f0e69cd7dec170d778fdbca95e \
+ --hash=sha256:ecd27a66740ffd621d20b9a2f2b5ee4129a56e27bfb9458a3bcc2e45794c96cb \
+ --hash=sha256:f009c69bc8c53db5dfab72ac760895dc1f2bc1b62ab7408b253c8d1ec52459fc \
+ --hash=sha256:f16bc1334853e91ddaaa1217045dd7be166170beec337576818461268a3de67f \
+ --hash=sha256:f19169781dddae7478a32301b499b2858bc52fc45a112955e798ee307e294977 \
+ --hash=sha256:fa3060d885657abc549b2a0f8e1b79699290e5d83845141717c6c90c2df38311 \
+ --hash=sha256:fa41a64ac5b08b292906e248549ab48b69c5428f3987b09689ab2441f267d04d \
+ --hash=sha256:fbf15aff64a163db29a91ed0868af181d6f68ec1a3a7d5afcfe4501252840bad \
+ --hash=sha256:fe00a9057d100e69b4ae4a094203a708d65b0f345ed546fdef86498bf5390982
+ # via
+ # jsonschema
+ # referencing
+rubin-nublado-client==8.0.2 \
+ --hash=sha256:1b3c68891899beb6f9eb7a183f68d11849723061144f33d04f7f8e9a3f22f3de \
+ --hash=sha256:ef2e27d7ec44a0db4ad55e1ddc5968604e19cf614b13adcab21d73a5a6affa75
# via -r requirements/main.in
-sniffio==1.3.0 \
- --hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \
- --hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384
+safir==6.5.1 \
+ --hash=sha256:8c4b85f07e2343848f598bbcba832fec6725219c4234e2a05e97e5623347d6bf \
+ --hash=sha256:e00167de168115477309436f136bd3c01623dfc362b9d32bc6c87ea65857f993
+ # via
+ # -r requirements/main.in
+ # rubin-nublado-client
+safir-arq==6.5.1 \
+ --hash=sha256:365ac4eaa562214cdf9f54eb868f54caf46adf3905119826a431794a75110e5a \
+ --hash=sha256:599619c1e84bbd26514d5af6f183f4bb513c6d5f7bf08cd9c6b17c1769a8eb8a
+ # via safir
+safir-logging==6.5.1 \
+ --hash=sha256:b056306de26627e29bd6a6d04b1144456a1319ec0e15a67ebbc12b43362a27cd \
+ --hash=sha256:ff591f0247fda10842835e714a6dbf601a894432d33d6d98e20fe035a5ad952c
+ # via safir
+shortuuid==1.0.13 \
+ --hash=sha256:3bb9cf07f606260584b1df46399c0b87dd84773e7b25912b7e391e30797c5e72 \
+ --hash=sha256:a482a497300b49b4953e15108a7913244e1bb0d41f9d332f5e9925dba33a3c5a
+ # via rubin-nublado-client
+six==1.16.0 \
+ --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
+ --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
+ # via python-dateutil
+sniffio==1.3.1 \
+ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \
+ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc
# via
# anyio
# httpx
-starlette==0.32.0.post1 \
- --hash=sha256:cd0cb10ddb49313f609cedfac62c8c12e56c7314b66d89bb077ba228bada1b09 \
- --hash=sha256:e54e2b7e2fb06dff9eac40133583f10dfa05913f5a85bf26f427c7a40a9a3d02
+starlette==0.41.2 \
+ --hash=sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62 \
+ --hash=sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d
# via
# -r requirements/main.in
# fastapi
# safir
-structlog==23.3.0 \
- --hash=sha256:24b42b914ac6bc4a4e6f716e82ac70d7fb1e8c3b1035a765591953bfc37101a5 \
- --hash=sha256:d6922a88ceabef5b13b9eda9c4043624924f60edbb00397f4d193bd754cde60a
- # via safir
-typing-extensions==4.9.0 \
- --hash=sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783 \
- --hash=sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd
+structlog==24.4.0 \
+ --hash=sha256:597f61e80a91cc0749a9fd2a098ed76715a1c8a01f73e336b746504d1aad7610 \
+ --hash=sha256:b27bfecede327a6d2da5fbc96bd859f114ecc398a6389d664f62085ee7ae6fc4
# via
- # arq
+ # rubin-nublado-client
+ # safir
+ # safir-arq
+ # safir-logging
+typing-extensions==4.12.2 \
+ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
+ --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
+ # via
+ # aiokafka
+ # dataclasses-avroschema
# fastapi
+ # faststream
# pydantic
# pydantic-core
uritemplate==4.1.1 \
--hash=sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0 \
--hash=sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e
# via gidgethub
-uvicorn[standard]==0.25.0 \
- --hash=sha256:6dddbad1d7ee0f5140aba5ec138ddc9612c5109399903828b4874c9937f009c2 \
- --hash=sha256:ce107f5d9bd02b4636001a77a4e74aab5e1e2b146868ebbad565237145af444c
+uvicorn==0.32.0 \
+ --hash=sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82 \
+ --hash=sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e
# via -r requirements/main.in
-uvloop==0.19.0 \
- --hash=sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd \
- --hash=sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec \
- --hash=sha256:13dfdf492af0aa0a0edf66807d2b465607d11c4fa48f4a1fd41cbea5b18e8e8b \
- --hash=sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc \
- --hash=sha256:271718e26b3e17906b28b67314c45d19106112067205119dddbd834c2b7ce797 \
- --hash=sha256:2df95fca285a9f5bfe730e51945ffe2fa71ccbfdde3b0da5772b4ee4f2e770d5 \
- --hash=sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2 \
- --hash=sha256:34175c9fd2a4bc3adc1380e1261f60306344e3407c20a4d684fd5f3be010fa3d \
- --hash=sha256:45bf4c24c19fb8a50902ae37c5de50da81de4922af65baf760f7c0c42e1088be \
- --hash=sha256:472d61143059c84947aa8bb74eabbace30d577a03a1805b77933d6bd13ddebbd \
- --hash=sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12 \
- --hash=sha256:492e2c32c2af3f971473bc22f086513cedfc66a130756145a931a90c3958cb17 \
- --hash=sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef \
- --hash=sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24 \
- --hash=sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428 \
- --hash=sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1 \
- --hash=sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849 \
- --hash=sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593 \
- --hash=sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd \
- --hash=sha256:6e3d4e85ac060e2342ff85e90d0c04157acb210b9ce508e784a944f852a40e67 \
- --hash=sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6 \
- --hash=sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3 \
- --hash=sha256:78ab247f0b5671cc887c31d33f9b3abfb88d2614b84e4303f1a63b46c046c8bd \
- --hash=sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8 \
- --hash=sha256:8ca4956c9ab567d87d59d49fa3704cf29e37109ad348f2d5223c9bf761a332e7 \
- --hash=sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533 \
- --hash=sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957 \
- --hash=sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650 \
- --hash=sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e \
- --hash=sha256:e27f100e1ff17f6feeb1f33968bc185bf8ce41ca557deee9d9bbbffeb72030b7 \
- --hash=sha256:f467a5fd23b4fc43ed86342641f3936a68ded707f4627622fa3f82a120e18256
+uvloop==0.21.0 \
+ --hash=sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0 \
+ --hash=sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f \
+ --hash=sha256:10da8046cc4a8f12c91a1c39d1dd1585c41162a15caaef165c2174db9ef18bdc \
+ --hash=sha256:17df489689befc72c39a08359efac29bbee8eee5209650d4b9f34df73d22e414 \
+ --hash=sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f \
+ --hash=sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d \
+ --hash=sha256:221f4f2a1f46032b403bf3be628011caf75428ee3cc204a22addf96f586b19fd \
+ --hash=sha256:2d1f581393673ce119355d56da84fe1dd9d2bb8b3d13ce792524e1607139feff \
+ --hash=sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c \
+ --hash=sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3 \
+ --hash=sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d \
+ --hash=sha256:460def4412e473896ef179a1671b40c039c7012184b627898eea5072ef6f017a \
+ --hash=sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb \
+ --hash=sha256:46923b0b5ee7fc0020bef24afe7836cb068f5050ca04caf6b487c513dc1a20b2 \
+ --hash=sha256:53e420a3afe22cdcf2a0f4846e377d16e718bc70103d7088a4f7623567ba5fb0 \
+ --hash=sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6 \
+ --hash=sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c \
+ --hash=sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af \
+ --hash=sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc \
+ --hash=sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb \
+ --hash=sha256:88cb67cdbc0e483da00af0b2c3cdad4b7c61ceb1ee0f33fe00e09c81e3a6cb75 \
+ --hash=sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb \
+ --hash=sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553 \
+ --hash=sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e \
+ --hash=sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6 \
+ --hash=sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d \
+ --hash=sha256:bc09f0ff191e61c2d592a752423c767b4ebb2986daa9ed62908e2b1b9a9ae206 \
+ --hash=sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc \
+ --hash=sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281 \
+ --hash=sha256:c097078b8031190c934ed0ebfee8cc5f9ba9642e6eb88322b9958b649750f72b \
+ --hash=sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8 \
+ --hash=sha256:e678ad6fe52af2c58d2ae3c73dc85524ba8abe637f134bf3564ed07f555c5e79 \
+ --hash=sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f \
+ --hash=sha256:f0ce1b49560b1d2d8a2977e3ba4afb2414fb46b86a1b64056bc4ab929efdafbe \
+ --hash=sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26 \
+ --hash=sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816 \
+ --hash=sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2
# via uvicorn
-watchfiles==0.21.0 \
- --hash=sha256:02b73130687bc3f6bb79d8a170959042eb56eb3a42df3671c79b428cd73f17cc \
- --hash=sha256:02d91cbac553a3ad141db016e3350b03184deaafeba09b9d6439826ee594b365 \
- --hash=sha256:06247538e8253975bdb328e7683f8515ff5ff041f43be6c40bff62d989b7d0b0 \
- --hash=sha256:08dca260e85ffae975448e344834d765983237ad6dc308231aa16e7933db763e \
- --hash=sha256:0d9ac347653ebd95839a7c607608703b20bc07e577e870d824fa4801bc1cb124 \
- --hash=sha256:0dd5fad9b9c0dd89904bbdea978ce89a2b692a7ee8a0ce19b940e538c88a809c \
- --hash=sha256:11cd0c3100e2233e9c53106265da31d574355c288e15259c0d40a4405cbae317 \
- --hash=sha256:18722b50783b5e30a18a8a5db3006bab146d2b705c92eb9a94f78c72beb94094 \
- --hash=sha256:18d5b4da8cf3e41895b34e8c37d13c9ed294954907929aacd95153508d5d89d7 \
- --hash=sha256:1ad7247d79f9f55bb25ab1778fd47f32d70cf36053941f07de0b7c4e96b5d235 \
- --hash=sha256:1b8d1eae0f65441963d805f766c7e9cd092f91e0c600c820c764a4ff71a0764c \
- --hash=sha256:1bd467213195e76f838caf2c28cd65e58302d0254e636e7c0fca81efa4a2e62c \
- --hash=sha256:1c9198c989f47898b2c22201756f73249de3748e0fc9de44adaf54a8b259cc0c \
- --hash=sha256:1fd9a5205139f3c6bb60d11f6072e0552f0a20b712c85f43d42342d162be1235 \
- --hash=sha256:214cee7f9e09150d4fb42e24919a1e74d8c9b8a9306ed1474ecaddcd5479c293 \
- --hash=sha256:27b4035013f1ea49c6c0b42d983133b136637a527e48c132d368eb19bf1ac6aa \
- --hash=sha256:3a23092a992e61c3a6a70f350a56db7197242f3490da9c87b500f389b2d01eef \
- --hash=sha256:3ad692bc7792be8c32918c699638b660c0de078a6cbe464c46e1340dadb94c19 \
- --hash=sha256:3ccceb50c611c433145502735e0370877cced72a6c70fd2410238bcbc7fe51d8 \
- --hash=sha256:3d0f32ebfaa9c6011f8454994f86108c2eb9c79b8b7de00b36d558cadcedaa3d \
- --hash=sha256:3f92944efc564867bbf841c823c8b71bb0be75e06b8ce45c084b46411475a915 \
- --hash=sha256:40bca549fdc929b470dd1dbfcb47b3295cb46a6d2c90e50588b0a1b3bd98f429 \
- --hash=sha256:43babacef21c519bc6631c5fce2a61eccdfc011b4bcb9047255e9620732c8097 \
- --hash=sha256:4566006aa44cb0d21b8ab53baf4b9c667a0ed23efe4aaad8c227bfba0bf15cbe \
- --hash=sha256:49f56e6ecc2503e7dbe233fa328b2be1a7797d31548e7a193237dcdf1ad0eee0 \
- --hash=sha256:4c48a10d17571d1275701e14a601e36959ffada3add8cdbc9e5061a6e3579a5d \
- --hash=sha256:4ea10a29aa5de67de02256a28d1bf53d21322295cb00bd2d57fcd19b850ebd99 \
- --hash=sha256:511f0b034120cd1989932bf1e9081aa9fb00f1f949fbd2d9cab6264916ae89b1 \
- --hash=sha256:51ddac60b96a42c15d24fbdc7a4bfcd02b5a29c047b7f8bf63d3f6f5a860949a \
- --hash=sha256:57d430f5fb63fea141ab71ca9c064e80de3a20b427ca2febcbfcef70ff0ce895 \
- --hash=sha256:59137c0c6826bd56c710d1d2bda81553b5e6b7c84d5a676747d80caf0409ad94 \
- --hash=sha256:5a03651352fc20975ee2a707cd2d74a386cd303cc688f407296064ad1e6d1562 \
- --hash=sha256:5eb86c6acb498208e7663ca22dbe68ca2cf42ab5bf1c776670a50919a56e64ab \
- --hash=sha256:642d66b75eda909fd1112d35c53816d59789a4b38c141a96d62f50a3ef9b3360 \
- --hash=sha256:6674b00b9756b0af620aa2a3346b01f8e2a3dc729d25617e1b89cf6af4a54eb1 \
- --hash=sha256:668c265d90de8ae914f860d3eeb164534ba2e836811f91fecc7050416ee70aa7 \
- --hash=sha256:66fac0c238ab9a2e72d026b5fb91cb902c146202bbd29a9a1a44e8db7b710b6f \
- --hash=sha256:6c107ea3cf2bd07199d66f156e3ea756d1b84dfd43b542b2d870b77868c98c03 \
- --hash=sha256:6c889025f59884423428c261f212e04d438de865beda0b1e1babab85ef4c0f01 \
- --hash=sha256:6cb8fdc044909e2078c248986f2fc76f911f72b51ea4a4fbbf472e01d14faa58 \
- --hash=sha256:6e9be3ef84e2bb9710f3f777accce25556f4a71e15d2b73223788d528fcc2052 \
- --hash=sha256:7f762a1a85a12cc3484f77eee7be87b10f8c50b0b787bb02f4e357403cad0c0e \
- --hash=sha256:83a696da8922314ff2aec02987eefb03784f473281d740bf9170181829133765 \
- --hash=sha256:853853cbf7bf9408b404754b92512ebe3e3a83587503d766d23e6bf83d092ee6 \
- --hash=sha256:8ad3fe0a3567c2f0f629d800409cd528cb6251da12e81a1f765e5c5345fd0137 \
- --hash=sha256:8c6ed10c2497e5fedadf61e465b3ca12a19f96004c15dcffe4bd442ebadc2d85 \
- --hash=sha256:8d5f400326840934e3507701f9f7269247f7c026d1b6cfd49477d2be0933cfca \
- --hash=sha256:927c589500f9f41e370b0125c12ac9e7d3a2fd166b89e9ee2828b3dda20bfe6f \
- --hash=sha256:9a0aa47f94ea9a0b39dd30850b0adf2e1cd32a8b4f9c7aa443d852aacf9ca214 \
- --hash=sha256:9b37a7ba223b2f26122c148bb8d09a9ff312afca998c48c725ff5a0a632145f7 \
- --hash=sha256:9c873345680c1b87f1e09e0eaf8cf6c891b9851d8b4d3645e7efe2ec20a20cc7 \
- --hash=sha256:9d09869f2c5a6f2d9df50ce3064b3391d3ecb6dced708ad64467b9e4f2c9bef3 \
- --hash=sha256:9d353c4cfda586db2a176ce42c88f2fc31ec25e50212650c89fdd0f560ee507b \
- --hash=sha256:a1e3014a625bcf107fbf38eece0e47fa0190e52e45dc6eee5a8265ddc6dc5ea7 \
- --hash=sha256:a3b9bec9579a15fb3ca2d9878deae789df72f2b0fdaf90ad49ee389cad5edab6 \
- --hash=sha256:ab03a90b305d2588e8352168e8c5a1520b721d2d367f31e9332c4235b30b8994 \
- --hash=sha256:aff06b2cac3ef4616e26ba17a9c250c1fe9dd8a5d907d0193f84c499b1b6e6a9 \
- --hash=sha256:b3cab0e06143768499384a8a5efb9c4dc53e19382952859e4802f294214f36ec \
- --hash=sha256:b4a21f71885aa2744719459951819e7bf5a906a6448a6b2bbce8e9cc9f2c8128 \
- --hash=sha256:b6d45d9b699ecbac6c7bd8e0a2609767491540403610962968d258fd6405c17c \
- --hash=sha256:be6dd5d52b73018b21adc1c5d28ac0c68184a64769052dfeb0c5d9998e7f56a2 \
- --hash=sha256:c550a56bf209a3d987d5a975cdf2063b3389a5d16caf29db4bdddeae49f22078 \
- --hash=sha256:c76c635fabf542bb78524905718c39f736a98e5ab25b23ec6d4abede1a85a6a3 \
- --hash=sha256:c81818595eff6e92535ff32825f31c116f867f64ff8cdf6562cd1d6b2e1e8f3e \
- --hash=sha256:cfb92d49dbb95ec7a07511bc9efb0faff8fe24ef3805662b8d6808ba8409a71a \
- --hash=sha256:d23bcd6c8eaa6324fe109d8cac01b41fe9a54b8c498af9ce464c1aeeb99903d6 \
- --hash=sha256:d5b1dc0e708fad9f92c296ab2f948af403bf201db8fb2eb4c8179db143732e49 \
- --hash=sha256:d78f30cbe8b2ce770160d3c08cff01b2ae9306fe66ce899b73f0409dc1846c1b \
- --hash=sha256:d8f57c4461cd24fda22493109c45b3980863c58a25b8bec885ca8bea6b8d4b28 \
- --hash=sha256:d9792dff410f266051025ecfaa927078b94cc7478954b06796a9756ccc7e14a9 \
- --hash=sha256:e7941bbcfdded9c26b0bf720cb7e6fd803d95a55d2c14b4bd1f6a2772230c586 \
- --hash=sha256:ebe684d7d26239e23d102a2bad2a358dedf18e462e8808778703427d1f584400 \
- --hash=sha256:ec8c8900dc5c83650a63dd48c4d1d245343f904c4b64b48798c67a3767d7e165 \
- --hash=sha256:f564bf68404144ea6b87a78a3f910cc8de216c6b12a4cf0b27718bf4ec38d303 \
- --hash=sha256:fd7ac678b92b29ba630d8c842d8ad6c555abda1b9ef044d6cc092dacbfc9719d
+watchfiles==0.24.0 \
+ --hash=sha256:01550ccf1d0aed6ea375ef259706af76ad009ef5b0203a3a4cce0f6024f9b68a \
+ --hash=sha256:01def80eb62bd5db99a798d5e1f5f940ca0a05986dcfae21d833af7a46f7ee22 \
+ --hash=sha256:07cdef0c84c03375f4e24642ef8d8178e533596b229d32d2bbd69e5128ede02a \
+ --hash=sha256:083dc77dbdeef09fa44bb0f4d1df571d2e12d8a8f985dccde71ac3ac9ac067a0 \
+ --hash=sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827 \
+ --hash=sha256:21ab23fdc1208086d99ad3f69c231ba265628014d4aed31d4e8746bd59e88cd1 \
+ --hash=sha256:2dadf8a8014fde6addfd3c379e6ed1a981c8f0a48292d662e27cabfe4239c83c \
+ --hash=sha256:2e28d91ef48eab0afb939fa446d8ebe77e2f7593f5f463fd2bb2b14132f95b6e \
+ --hash=sha256:2efec17819b0046dde35d13fb8ac7a3ad877af41ae4640f4109d9154ed30a188 \
+ --hash=sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b \
+ --hash=sha256:316449aefacf40147a9efaf3bd7c9bdd35aaba9ac5d708bd1eb5763c9a02bef5 \
+ --hash=sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90 \
+ --hash=sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef \
+ --hash=sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b \
+ --hash=sha256:3770e260b18e7f4e576edca4c0a639f704088602e0bc921c5c2e721e3acb8d15 \
+ --hash=sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48 \
+ --hash=sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e \
+ --hash=sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df \
+ --hash=sha256:449f43f49c8ddca87c6b3980c9284cab6bd1f5c9d9a2b00012adaaccd5e7decd \
+ --hash=sha256:4933a508d2f78099162da473841c652ad0de892719043d3f07cc83b33dfd9d91 \
+ --hash=sha256:49d617df841a63b4445790a254013aea2120357ccacbed00253f9c2b5dc24e2d \
+ --hash=sha256:49fb58bcaa343fedc6a9e91f90195b20ccb3135447dc9e4e2570c3a39565853e \
+ --hash=sha256:4a7fa2bc0efef3e209a8199fd111b8969fe9db9c711acc46636686331eda7dd4 \
+ --hash=sha256:4abf4ad269856618f82dee296ac66b0cd1d71450fc3c98532d93798e73399b7a \
+ --hash=sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370 \
+ --hash=sha256:4d28cea3c976499475f5b7a2fec6b3a36208656963c1a856d328aeae056fc5c1 \
+ --hash=sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea \
+ --hash=sha256:54ca90a9ae6597ae6dc00e7ed0a040ef723f84ec517d3e7ce13e63e4bc82fa04 \
+ --hash=sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896 \
+ --hash=sha256:5c51749f3e4e269231510da426ce4a44beb98db2dce9097225c338f815b05d4f \
+ --hash=sha256:632676574429bee8c26be8af52af20e0c718cc7f5f67f3fb658c71928ccd4f7f \
+ --hash=sha256:6509ed3f467b79d95fc62a98229f79b1a60d1b93f101e1c61d10c95a46a84f43 \
+ --hash=sha256:6bdcfa3cd6fdbdd1a068a52820f46a815401cbc2cb187dd006cb076675e7b735 \
+ --hash=sha256:7138eff8baa883aeaa074359daabb8b6c1e73ffe69d5accdc907d62e50b1c0da \
+ --hash=sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a \
+ --hash=sha256:73bde715f940bea845a95247ea3e5eb17769ba1010efdc938ffcb967c634fa61 \
+ --hash=sha256:78470906a6be5199524641f538bd2c56bb809cd4bf29a566a75051610bc982c3 \
+ --hash=sha256:7ae3e208b31be8ce7f4c2c0034f33406dd24fbce3467f77223d10cd86778471c \
+ --hash=sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f \
+ --hash=sha256:82ae557a8c037c42a6ef26c494d0631cacca040934b101d001100ed93d43f361 \
+ --hash=sha256:82b2509f08761f29a0fdad35f7e1638b8ab1adfa2666d41b794090361fb8b855 \
+ --hash=sha256:8360f7314a070c30e4c976b183d1d8d1585a4a50c5cb603f431cebcbb4f66327 \
+ --hash=sha256:85d5f0c7771dcc7a26c7a27145059b6bb0ce06e4e751ed76cdf123d7039b60b5 \
+ --hash=sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab \
+ --hash=sha256:9301c689051a4857d5b10777da23fafb8e8e921bcf3abe6448a058d27fb67633 \
+ --hash=sha256:951088d12d339690a92cef2ec5d3cfd957692834c72ffd570ea76a6790222777 \
+ --hash=sha256:95cf3b95ea665ab03f5a54765fa41abf0529dbaf372c3b83d91ad2cfa695779b \
+ --hash=sha256:96619302d4374de5e2345b2b622dc481257a99431277662c30f606f3e22f42be \
+ --hash=sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f \
+ --hash=sha256:9a60e2bf9dc6afe7f743e7c9b149d1fdd6dbf35153c78fe3a14ae1a9aee3d98b \
+ --hash=sha256:9f895d785eb6164678ff4bb5cc60c5996b3ee6df3edb28dcdeba86a13ea0465e \
+ --hash=sha256:a2a9891723a735d3e2540651184be6fd5b96880c08ffe1a98bae5017e65b544b \
+ --hash=sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366 \
+ --hash=sha256:aa0fd7248cf533c259e59dc593a60973a73e881162b1a2f73360547132742823 \
+ --hash=sha256:acbfa31e315a8f14fe33e3542cbcafc55703b8f5dcbb7c1eecd30f141df50db3 \
+ --hash=sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1 \
+ --hash=sha256:b3ef2c69c655db63deb96b3c3e587084612f9b1fa983df5e0c3379d41307467f \
+ --hash=sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418 \
+ --hash=sha256:b665caeeda58625c3946ad7308fbd88a086ee51ccb706307e5b1fa91556ac886 \
+ --hash=sha256:b74fdffce9dfcf2dc296dec8743e5b0332d15df19ae464f0e249aa871fc1c571 \
+ --hash=sha256:b995bfa6bf01a9e09b884077a6d37070464b529d8682d7691c2d3b540d357a0c \
+ --hash=sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94 \
+ --hash=sha256:bdcd5538e27f188dd3c804b4a8d5f52a7fc7f87e7fd6b374b8e36a4ca03db428 \
+ --hash=sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234 \
+ --hash=sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6 \
+ --hash=sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968 \
+ --hash=sha256:d337193bbf3e45171c8025e291530fb7548a93c45253897cd764a6a71c937ed9 \
+ --hash=sha256:d3dcb774e3568477275cc76554b5a565024b8ba3a0322f77c246bc7111c5bb9c \
+ --hash=sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e \
+ --hash=sha256:d7a2e3b7f5703ffbd500dabdefcbc9eafeff4b9444bbdd5d83d79eedf8428fab \
+ --hash=sha256:d831ee0a50946d24a53821819b2327d5751b0c938b12c0653ea5be7dea9c82ec \
+ --hash=sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444 \
+ --hash=sha256:e5171ef898299c657685306d8e1478a45e9303ddcd8ac5fed5bd52ad4ae0b69b \
+ --hash=sha256:e94e98c7cb94cfa6e071d401ea3342767f28eb5a06a58fafdc0d2a4974f4f35c \
+ --hash=sha256:ec39698c45b11d9694a1b635a70946a5bad066b593af863460a8e600f0dff1ca \
+ --hash=sha256:ed9aba6e01ff6f2e8285e5aa4154e2970068fe0fc0998c4380d0e6278222269b \
+ --hash=sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18 \
+ --hash=sha256:ee82c98bed9d97cd2f53bdb035e619309a098ea53ce525833e26b93f673bc318 \
+ --hash=sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07 \
+ --hash=sha256:f7d9b87c4c55e3ea8881dfcbf6d61ea6775fffed1fedffaa60bd047d3c08c430 \
+ --hash=sha256:f83df90191d67af5a831da3a33dd7628b02a95450e168785586ed51e6d28943c \
+ --hash=sha256:fca9433a45f18b7c779d2bae7beeec4f740d28b788b117a48368d95a3233ed83 \
+ --hash=sha256:fd92bbaa2ecdb7864b7600dcdb6f2f1db6e0346ed425fbd01085be04c63f0b05
# via uvicorn
-websockets==12.0 \
- --hash=sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b \
- --hash=sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6 \
- --hash=sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df \
- --hash=sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b \
- --hash=sha256:1a9d160fd080c6285e202327aba140fc9a0d910b09e423afff4ae5cbbf1c7205 \
- --hash=sha256:1bf386089178ea69d720f8db6199a0504a406209a0fc23e603b27b300fdd6892 \
- --hash=sha256:1df2fbd2c8a98d38a66f5238484405b8d1d16f929bb7a33ed73e4801222a6f53 \
- --hash=sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2 \
- --hash=sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed \
- --hash=sha256:23509452b3bc38e3a057382c2e941d5ac2e01e251acce7adc74011d7d8de434c \
- --hash=sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd \
- --hash=sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b \
- --hash=sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931 \
- --hash=sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30 \
- --hash=sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370 \
- --hash=sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be \
- --hash=sha256:2e5fc14ec6ea568200ea4ef46545073da81900a2b67b3e666f04adf53ad452ec \
- --hash=sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf \
- --hash=sha256:3c6cc1360c10c17463aadd29dd3af332d4a1adaa8796f6b0e9f9df1fdb0bad62 \
- --hash=sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b \
- --hash=sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402 \
- --hash=sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f \
- --hash=sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123 \
- --hash=sha256:46e71dbbd12850224243f5d2aeec90f0aaa0f2dde5aeeb8fc8df21e04d99eff9 \
- --hash=sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603 \
- --hash=sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45 \
- --hash=sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558 \
- --hash=sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4 \
- --hash=sha256:5f6ffe2c6598f7f7207eef9a1228b6f5c818f9f4d53ee920aacd35cec8110438 \
- --hash=sha256:604428d1b87edbf02b233e2c207d7d528460fa978f9e391bd8aaf9c8311de137 \
- --hash=sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480 \
- --hash=sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447 \
- --hash=sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8 \
- --hash=sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04 \
- --hash=sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c \
- --hash=sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb \
- --hash=sha256:7fa3d25e81bfe6a89718e9791128398a50dec6d57faf23770787ff441d851967 \
- --hash=sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b \
- --hash=sha256:8572132c7be52632201a35f5e08348137f658e5ffd21f51f94572ca6c05ea81d \
- --hash=sha256:87b4aafed34653e465eb77b7c93ef058516cb5acf3eb21e42f33928616172def \
- --hash=sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c \
- --hash=sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92 \
- --hash=sha256:9edf3fc590cc2ec20dc9d7a45108b5bbaf21c0d89f9fd3fd1685e223771dc0b2 \
- --hash=sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113 \
- --hash=sha256:a02413bc474feda2849c59ed2dfb2cddb4cd3d2f03a2fedec51d6e959d9b608b \
- --hash=sha256:a1d9697f3337a89691e3bd8dc56dea45a6f6d975f92e7d5f773bc715c15dde28 \
- --hash=sha256:a571f035a47212288e3b3519944f6bf4ac7bc7553243e41eac50dd48552b6df7 \
- --hash=sha256:ab3d732ad50a4fbd04a4490ef08acd0517b6ae6b77eb967251f4c263011a990d \
- --hash=sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f \
- --hash=sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468 \
- --hash=sha256:b2ee7288b85959797970114deae81ab41b731f19ebcd3bd499ae9ca0e3f1d2c8 \
- --hash=sha256:b81f90dcc6c85a9b7f29873beb56c94c85d6f0dac2ea8b60d995bd18bf3e2aae \
- --hash=sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611 \
- --hash=sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d \
- --hash=sha256:bbe6013f9f791944ed31ca08b077e26249309639313fff132bfbf3ba105673b9 \
- --hash=sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca \
- --hash=sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f \
- --hash=sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2 \
- --hash=sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077 \
- --hash=sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2 \
- --hash=sha256:cbe83a6bbdf207ff0541de01e11904827540aa069293696dd528a6640bd6a5f6 \
- --hash=sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374 \
- --hash=sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc \
- --hash=sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e \
- --hash=sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53 \
- --hash=sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399 \
- --hash=sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547 \
- --hash=sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3 \
- --hash=sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870 \
- --hash=sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5 \
- --hash=sha256:fc4e7fa5414512b481a2483775a8e8be7803a35b30ca805afa4998a84f9fd9e8 \
- --hash=sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7
+websockets==13.1 \
+ --hash=sha256:004280a140f220c812e65f36944a9ca92d766b6cc4560be652a0a3883a79ed8a \
+ --hash=sha256:035233b7531fb92a76beefcbf479504db8c72eb3bff41da55aecce3a0f729e54 \
+ --hash=sha256:149e622dc48c10ccc3d2760e5f36753db9cacf3ad7bc7bbbfd7d9c819e286f23 \
+ --hash=sha256:163e7277e1a0bd9fb3c8842a71661ad19c6aa7bb3d6678dc7f89b17fbcc4aeb7 \
+ --hash=sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135 \
+ --hash=sha256:1971e62d2caa443e57588e1d82d15f663b29ff9dfe7446d9964a4b6f12c1e700 \
+ --hash=sha256:204e5107f43095012b00f1451374693267adbb832d29966a01ecc4ce1db26faf \
+ --hash=sha256:2510c09d8e8df777177ee3d40cd35450dc169a81e747455cc4197e63f7e7bfe5 \
+ --hash=sha256:25c35bf84bf7c7369d247f0b8cfa157f989862c49104c5cf85cb5436a641d93e \
+ --hash=sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c \
+ --hash=sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02 \
+ --hash=sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a \
+ --hash=sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418 \
+ --hash=sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f \
+ --hash=sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3 \
+ --hash=sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68 \
+ --hash=sha256:4059f790b6ae8768471cddb65d3c4fe4792b0ab48e154c9f0a04cefaabcd5978 \
+ --hash=sha256:459bf774c754c35dbb487360b12c5727adab887f1622b8aed5755880a21c4a20 \
+ --hash=sha256:463e1c6ec853202dd3657f156123d6b4dad0c546ea2e2e38be2b3f7c5b8e7295 \
+ --hash=sha256:4676df3fe46956fbb0437d8800cd5f2b6d41143b6e7e842e60554398432cf29b \
+ --hash=sha256:485307243237328c022bc908b90e4457d0daa8b5cf4b3723fd3c4a8012fce4c6 \
+ --hash=sha256:48a2ef1381632a2f0cb4efeff34efa97901c9fbc118e01951ad7cfc10601a9bb \
+ --hash=sha256:4b889dbd1342820cc210ba44307cf75ae5f2f96226c0038094455a96e64fb07a \
+ --hash=sha256:586a356928692c1fed0eca68b4d1c2cbbd1ca2acf2ac7e7ebd3b9052582deefa \
+ --hash=sha256:58cf7e75dbf7e566088b07e36ea2e3e2bd5676e22216e4cad108d4df4a7402a0 \
+ --hash=sha256:5993260f483d05a9737073be197371940c01b257cc45ae3f1d5d7adb371b266a \
+ --hash=sha256:5dd6da9bec02735931fccec99d97c29f47cc61f644264eb995ad6c0c27667238 \
+ --hash=sha256:5f2e75431f8dc4a47f31565a6e1355fb4f2ecaa99d6b89737527ea917066e26c \
+ --hash=sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084 \
+ --hash=sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19 \
+ --hash=sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d \
+ --hash=sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7 \
+ --hash=sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9 \
+ --hash=sha256:6d2aad13a200e5934f5a6767492fb07151e1de1d6079c003ab31e1823733ae79 \
+ --hash=sha256:6d6855bbe70119872c05107e38fbc7f96b1d8cb047d95c2c50869a46c65a8e96 \
+ --hash=sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6 \
+ --hash=sha256:730f42125ccb14602f455155084f978bd9e8e57e89b569b4d7f0f0c17a448ffe \
+ --hash=sha256:7a43cfdcddd07f4ca2b1afb459824dd3c6d53a51410636a2c7fc97b9a8cf4842 \
+ --hash=sha256:7bd6abf1e070a6b72bfeb71049d6ad286852e285f146682bf30d0296f5fbadfa \
+ --hash=sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3 \
+ --hash=sha256:7c65ffa900e7cc958cd088b9a9157a8141c991f8c53d11087e6fb7277a03f81d \
+ --hash=sha256:80c421e07973a89fbdd93e6f2003c17d20b69010458d3a8e37fb47874bd67d51 \
+ --hash=sha256:82d0ba76371769d6a4e56f7e83bb8e81846d17a6190971e38b5de108bde9b0d7 \
+ --hash=sha256:83f91d8a9bb404b8c2c41a707ac7f7f75b9442a0a876df295de27251a856ad09 \
+ --hash=sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096 \
+ --hash=sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9 \
+ --hash=sha256:9156c45750b37337f7b0b00e6248991a047be4aa44554c9886fe6bdd605aab3b \
+ --hash=sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5 \
+ --hash=sha256:95858ca14a9f6fa8413d29e0a585b31b278388aa775b8a81fa24830123874678 \
+ --hash=sha256:95df24ca1e1bd93bbca51d94dd049a984609687cb2fb08a7f2c56ac84e9816ea \
+ --hash=sha256:9b37c184f8b976f0c0a231a5f3d6efe10807d41ccbe4488df8c74174805eea7d \
+ --hash=sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49 \
+ --hash=sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc \
+ --hash=sha256:9ef8aa8bdbac47f4968a5d66462a2a0935d044bf35c0e5a8af152d58516dbeb5 \
+ --hash=sha256:a11e38ad8922c7961447f35c7b17bffa15de4d17c70abd07bfbe12d6faa3e027 \
+ --hash=sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0 \
+ --hash=sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878 \
+ --hash=sha256:a569eb1b05d72f9bce2ebd28a1ce2054311b66677fcd46cf36204ad23acead8c \
+ --hash=sha256:a7affedeb43a70351bb811dadf49493c9cfd1ed94c9c70095fd177e9cc1541fa \
+ --hash=sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f \
+ --hash=sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6 \
+ --hash=sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2 \
+ --hash=sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf \
+ --hash=sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708 \
+ --hash=sha256:bcc03c8b72267e97b49149e4863d57c2d77f13fae12066622dc78fe322490fe6 \
+ --hash=sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f \
+ --hash=sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd \
+ --hash=sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2 \
+ --hash=sha256:c7934fd0e920e70468e676fe7f1b7261c1efa0d6c037c6722278ca0228ad9d0d \
+ --hash=sha256:c7e72ce6bda6fb9409cc1e8164dd41d7c91466fb599eb047cfda72fe758a34a7 \
+ --hash=sha256:c90d6dec6be2c7d03378a574de87af9b1efea77d0c52a8301dd831ece938452f \
+ --hash=sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5 \
+ --hash=sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6 \
+ --hash=sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557 \
+ --hash=sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14 \
+ --hash=sha256:d8dbb1bf0c0a4ae8b40bdc9be7f644e2f3fb4e8a9aca7145bfa510d4a374eeb7 \
+ --hash=sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd \
+ --hash=sha256:deeb929efe52bed518f6eb2ddc00cc496366a14c726005726ad62c2dd9017a3c \
+ --hash=sha256:df01aea34b6e9e33572c35cd16bae5a47785e7d5c8cb2b54b2acdb9678315a17 \
+ --hash=sha256:e2620453c075abeb0daa949a292e19f56de518988e079c36478bacf9546ced23 \
+ --hash=sha256:e4450fc83a3df53dec45922b576e91e94f5578d06436871dce3a6be38e40f5db \
+ --hash=sha256:e54affdeb21026329fb0744ad187cf812f7d3c2aa702a5edb562b325191fcab6 \
+ --hash=sha256:e9875a0143f07d74dc5e1ded1c4581f0d9f7ab86c78994e2ed9e95050073c94d \
+ --hash=sha256:f1c3cf67185543730888b20682fb186fc8d0fa6f07ccc3ef4390831ab4b388d9 \
+ --hash=sha256:f48c749857f8fb598fb890a75f540e3221d0976ed0bf879cf3c7eef34151acee \
+ --hash=sha256:f779498eeec470295a2b1a5d97aa1bc9814ecd25e1eb637bd9d1c73a327387f6
# via
# -r requirements/main.in
+ # rubin-nublado-client
# uvicorn
diff --git a/requirements/tox.in b/requirements/tox.in
new file mode 100644
index 0000000..fde253f
--- /dev/null
+++ b/requirements/tox.in
@@ -0,0 +1,14 @@
+# -*- conf -*-
+#
+# Editable tox dependencies
+# Add tox and its plugins here. These will be installed in the user's venv for
+# local development and by CI when running tox actions.
+#
+# After editing, update requirements/dev.txt by running:
+# make update-deps
+
+-c main.txt
+-c dev.txt
+
+tox
+tox-uv
diff --git a/requirements/tox.txt b/requirements/tox.txt
new file mode 100644
index 0000000..19e74a4
--- /dev/null
+++ b/requirements/tox.txt
@@ -0,0 +1,89 @@
+# This file was autogenerated by uv via the following command:
+# uv pip compile --generate-hashes --output-file requirements/tox.txt requirements/tox.in
+cachetools==5.5.0 \
+ --hash=sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292 \
+ --hash=sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a
+ # via tox
+chardet==5.2.0 \
+ --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \
+ --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970
+ # via tox
+colorama==0.4.6 \
+ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+ # via tox
+distlib==0.3.9 \
+ --hash=sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87 \
+ --hash=sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403
+ # via
+ # -c requirements/dev.txt
+ # virtualenv
+filelock==3.16.1 \
+ --hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 \
+ --hash=sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435
+ # via
+ # -c requirements/dev.txt
+ # tox
+ # virtualenv
+packaging==24.1 \
+ --hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \
+ --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124
+ # via
+ # -c requirements/dev.txt
+ # -c requirements/main.txt
+ # pyproject-api
+ # tox
+ # tox-uv
+platformdirs==4.3.6 \
+ --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \
+ --hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb
+ # via
+ # -c requirements/dev.txt
+ # tox
+ # virtualenv
+pluggy==1.5.0 \
+ --hash=sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1 \
+ --hash=sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669
+ # via
+ # -c requirements/dev.txt
+ # tox
+pyproject-api==1.8.0 \
+ --hash=sha256:3d7d347a047afe796fd5d1885b1e391ba29be7169bd2f102fcd378f04273d228 \
+ --hash=sha256:77b8049f2feb5d33eefcc21b57f1e279636277a8ac8ad6b5871037b243778496
+ # via tox
+tox==4.23.2 \
+ --hash=sha256:452bc32bb031f2282881a2118923176445bac783ab97c874b8770ab4c3b76c38 \
+ --hash=sha256:86075e00e555df6e82e74cfc333917f91ecb47ffbc868dcafbd2672e332f4a2c
+ # via
+ # -r requirements/tox.in
+ # tox-uv
+tox-uv==1.16.0 \
+ --hash=sha256:71b2e2fa6c35c1360b91a302df1d65b3e5a1f656b321c5ebf7b84545804c9f01 \
+ --hash=sha256:e6f0b525a687e745ab878d07cbf5c7e85d582028d4a7c8935f95e84350651432
+ # via -r requirements/tox.in
+uv==0.4.29 \
+ --hash=sha256:0be21afa0e582ddc5badff6ef40c3c6784efc5feae4ad568307b668d40dc49bd \
+ --hash=sha256:246da468ac0d51e7fb257cd038db2f8d6376ae269a44d01f56776e32108aa9da \
+ --hash=sha256:24cccff9c248864ba0ab3429bae56314146c9494ce66a881d70ea8cf2805945f \
+ --hash=sha256:287dc3fd3f78093a5a82136f01cbd9f224e0905b38d3dcffdc96c08fbbe48ee9 \
+ --hash=sha256:3473b05142ba436ac30d036b7ab5e9bcfa97f63df5d1382f92e0a3e4aaa391bc \
+ --hash=sha256:668d3e6095c6f0cac6a831ef4030f7ad79442d1c84b9569f01f50b60c2d51a77 \
+ --hash=sha256:67dcfd253020e25ed1c49e5bd06406205c37264f99e14002de53a357cd1cdadf \
+ --hash=sha256:68d4967b5f0af8bd46085e0f3ded229026700668a97734a21c3d11a5fc350c47 \
+ --hash=sha256:6b03859068aaa08ca9907a51d403d54b0a9d8054091646845a9192f213f099d4 \
+ --hash=sha256:7060dfbad0bc26e9cecbb4f8482445c958071511f23728948478f81acfb29048 \
+ --hash=sha256:75927da78f74bb935314d236dc61ecdc192e878e06eb79585b6d9d5ee9829f98 \
+ --hash=sha256:8c71663c7df4f512c697de39a4926dc191897f5fede73644bb2329f532c1ebfa \
+ --hash=sha256:950bbfe1954e9c3a5d6c4777bb778b4c23d0dea9ad9f77622c45d4fbba433355 \
+ --hash=sha256:9c559b6fdc042add463e86afa1c210716f7020bfc2e96b00df5af7afcb587ce7 \
+ --hash=sha256:b5775db128b98251c3ea7874367fc20dce9f9aac3dbfa635e3ef4a1c56842d9c \
+ --hash=sha256:cfb797a87b55d96cc0593e9f29ab5d58454be74598ea0158e1b2f4f2dc97cede \
+ --hash=sha256:df35d9cbe4cfbb7bce287f56e3bb7a7cef0b7b5173ed889d936d4c470f2b1b83 \
+ --hash=sha256:f6224a322267570e0470c61008fd1c8e2f50bf073b339f4c3010da86aef3c44c
+ # via tox-uv
+virtualenv==20.27.1 \
+ --hash=sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba \
+ --hash=sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4
+ # via
+ # -c requirements/dev.txt
+ # tox
diff --git a/ruff-shared.toml b/ruff-shared.toml
new file mode 100644
index 0000000..823693a
--- /dev/null
+++ b/ruff-shared.toml
@@ -0,0 +1,125 @@
+# Generic shared Ruff configuration file. It should be possible to use this
+# file unmodified in different packages provided that one likes the style that
+# it enforces.
+#
+# This file should be used from pyproject.toml as follows:
+#
+# [tool.ruff]
+# extend = "ruff-shared.toml"
+#
+# It can then be extended with project-specific rules. A common additional
+# setting in pyproject.toml is tool.ruff.lint.extend-per-file-ignores, to add
+# additional project-specific ignore rules for specific paths.
+#
+# The rule used with Ruff configuration is to disable every non-deprecated
+# lint rule that has legitimate exceptions that are not dodgy code, rather
+# than cluttering code with noqa markers. This is therefore a reiatively
+# relaxed configuration that errs on the side of disabling legitimate rules.
+#
+# Reference for settings: https://docs.astral.sh/ruff/settings/
+# Reference for rules: https://docs.astral.sh/ruff/rules/
+exclude = ["docs/**"]
+line-length = 79
+target-version = "py312"
+
+[format]
+docstring-code-format = true
+
+[lint]
+ignore = [
+ "ANN401", # sometimes Any is the right type
+ "ARG001", # unused function arguments are often legitimate
+ "ARG002", # unused method arguments are often legitimate
+ "ARG005", # unused lambda arguments are often legitimate
+ "BLE001", # we want to catch and report Exception in background tasks
+ "C414", # nested sorted is how you sort by multiple keys with reverse
+ "D102", # sometimes we use docstring inheritence
+ "D104", # don't see the point of documenting every package
+ "D105", # our style doesn't require docstrings for magic methods
+ "D106", # Pydantic uses a nested Config class that doesn't warrant docs
+ "D205", # our documentation style allows a folded first line
+ "EM101", # justification (duplicate string in traceback) is silly
+ "EM102", # justification (duplicate string in traceback) is silly
+ "FBT003", # positional booleans are normal for Pydantic field defaults
+ "FIX002", # point of a TODO comment is that we're not ready to fix it
+ "G004", # forbidding logging f-strings is appealing, but not our style
+ "RET505", # disagree that omitting else always makes code more readable
+ "PLR0911", # often many returns is clearer and simpler style
+ "PLR0913", # factory pattern uses constructors with many arguments
+ "PLR2004", # too aggressive about magic values
+ "PLW0603", # yes global is discouraged but if needed, it's needed
+ "S105", # good idea but too many false positives on non-passwords
+ "S106", # good idea but too many false positives on non-passwords
+ "S107", # good idea but too many false positives on non-passwords
+ "S603", # not going to manually mark every subprocess call as reviewed
+ "S607", # using PATH is not a security vulnerability
+ "SIM102", # sometimes the formatting of nested if statements is clearer
+ "SIM117", # sometimes nested with contexts are clearer
+ "TCH001", # we decided to not maintain separate TYPE_CHECKING blocks
+ "TCH002", # we decided to not maintain separate TYPE_CHECKING blocks
+ "TCH003", # we decided to not maintain separate TYPE_CHECKING blocks
+ "TD003", # we don't require issues be created for TODOs
+ "TID252", # if we're going to use relative imports, use them always
+ "TRY003", # good general advice but lint is way too aggressive
+ "TRY301", # sometimes raising exceptions inside try is the best flow
+ "UP040", # PEP 695 type aliases not yet supported by mypy
+
+ # The following settings should be disabled when using ruff format
+ # per https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
+ "W191",
+ "E111",
+ "E114",
+ "E117",
+ "D206",
+ "D300",
+ "Q000",
+ "Q001",
+ "Q002",
+ "Q003",
+ "COM812",
+ "COM819",
+ "ISC001",
+ "ISC002",
+
+ # Temporary bug workarounds.
+ "S113", # https://github.com/astral-sh/ruff/issues/12210
+]
+select = ["ALL"]
+
+[lint.per-file-ignores]
+"src/*/handlers/**" = [
+ "D103", # FastAPI handlers should not have docstrings
+]
+"tests/**" = [
+ "C901", # tests are allowed to be complex, sometimes that's convenient
+ "D101", # tests don't need docstrings
+ "D103", # tests don't need docstrings
+ "PLR0915", # tests are allowed to be long, sometimes that's convenient
+ "PT012", # way too aggressive about limiting pytest.raises blocks
+ "S101", # tests should use assert
+ "S106", # tests are allowed to hard-code dummy passwords
+ "S301", # allow tests for whether code can be pickled
+ "SLF001", # tests are allowed to access private members
+]
+
+# These are too useful as attributes or methods to allow the conflict with the
+# built-in to rule out their use.
+[lint.flake8-builtins]
+builtins-ignorelist = [
+ "all",
+ "any",
+ "help",
+ "id",
+ "list",
+ "type",
+]
+
+[lint.flake8-pytest-style]
+fixture-parentheses = false
+mark-parentheses = false
+
+[lint.mccabe]
+max-complexity = 11
+
+[lint.pydocstyle]
+convention = "numpy"
diff --git a/src/noteburst/config.py b/src/noteburst/config.py
index 8e6169b..530f32c 100644
--- a/src/noteburst/config.py
+++ b/src/noteburst/config.py
@@ -4,7 +4,7 @@
from enum import Enum
from pathlib import Path
-from typing import Optional, Self
+from typing import Annotated, Self
from arq.connections import RedisSettings
from pydantic import Field, HttpUrl, RedisDsn, SecretStr, model_validator
@@ -49,57 +49,109 @@ class WorkerKeepAliveSetting(str, Enum):
class Config(BaseSettings):
"""Noteburst app configuration."""
- name: str = Field("Noteburst", alias="SAFIR_NAME")
+ name: Annotated[str, Field(alias="SAFIR_NAME")] = "Noteburst"
- profile: Profile = Field(Profile.production, alias="SAFIR_PROFILE")
-
- log_level: LogLevel = Field(LogLevel.INFO, alias="SAFIR_LOG_LEVEL")
-
- logger_name: str = "noteburst"
- """The root name of the Python logger, which is also the name of the
- root Python module.
- """
-
- path_prefix: str = Field("/noteburst", alias="NOTEBURST_PATH_PREFIX")
- """The URL path prefix where noteburst is hosted."""
-
- environment_url: HttpUrl = Field(alias="NOTEBURST_ENVIRONMENT_URL")
- """The base URL of the Rubin Science Platform environment.
-
- This is used for creating URLs to services, such as JupyterHub.
- """
-
- jupyterhub_path_prefix: str = Field(
- "/nb/",
- alias="NOTEBURST_JUPYTERHUB_PATH_PREFIX",
- description="The path prefix for the JupyterHub service.",
+ profile: Annotated[Profile, Field(alias="SAFIR_PROFILE")] = (
+ Profile.production
)
- nublado_controller_path_prefix: str = Field(
- "/nublado",
- alias="NOTEBURST_NUBLADO_CONTROLLER_PATH_PREFIX",
- description="The path prefix for the Nublado controller service.",
+ log_level: Annotated[LogLevel, Field(alias="SAFIR_LOG_LEVEL")] = (
+ LogLevel.INFO
)
- gafaelfawr_token: SecretStr = Field(alias="NOTEBURST_GAFAELFAWR_TOKEN")
- """This token is used to make an admin API call to Gafaelfawr to get a
- token for the user.
- """
+ logger_name: Annotated[
+ str,
+ Field(
+ description=(
+ "The root name of the Python logger, which is also the name "
+ "of the root Python module"
+ )
+ ),
+ ] = "noteburst"
+
+ path_prefix: Annotated[
+ str,
+ Field(
+ "/noteburst",
+ alias="NOTEBURST_PATH_PREFIX",
+ description="The URL path prefix where noteburst is hosted.",
+ ),
+ ] = "/noteburst"
+
+ environment_url: Annotated[
+ HttpUrl,
+ Field(
+ alias="NOTEBURST_ENVIRONMENT_URL",
+ description=(
+ "The base URL of the Rubin Science Platform environment. This "
+ "is used for creating URLs to services, such as JupyterHub."
+ ),
+ ),
+ ]
- redis_url: RedisDsn = Field(
- alias="NOTEBURST_REDIS_URL",
- # Preferred by mypy over a string default
- default_factory=lambda: RedisDsn("redis://localhost:6379/1"),
- )
- """URL for the redis instance, used by the worker queue."""
+ jupyterhub_path_prefix: Annotated[
+ str,
+ Field(
+ alias="NOTEBURST_JUPYTERHUB_PATH_PREFIX",
+ description="The path prefix for the JupyterHub service.",
+ ),
+ ] = "/nb/"
- arq_mode: ArqMode = Field(ArqMode.production, alias="NOTEBURST_ARQ_MODE")
+ nublado_controller_path_prefix: Annotated[
+ str,
+ Field(
+ alias="NOTEBURST_NUBLADO_CONTROLLER_PATH_PREFIX",
+ description="The path prefix for the Nublado controller service.",
+ ),
+ ] = "/nublado"
+
+ gafaelfawr_token: Annotated[
+ SecretStr,
+ Field(
+ alias="NOTEBURST_GAFAELFAWR_TOKEN",
+ description=(
+ "This token is used to make an admin API call to Gafaelfawr "
+ "to get a token for the user."
+ ),
+ ),
+ ]
+
+ redis_url: Annotated[
+ RedisDsn,
+ Field(
+ alias="NOTEBURST_REDIS_URL",
+ # Preferred by mypy over a string default
+ default_factory=lambda: RedisDsn("redis://localhost:6379/1"),
+ description=(
+ "URL for the redis instance, used by the worker queue.",
+ ),
+ ),
+ ]
+
+ arq_mode: Annotated[
+ ArqMode,
+ Field(
+ alias="NOTEBURST_ARQ_MODE",
+ description=(
+ "The Arq mode. Use 'test' to mock arq/redis for testing."
+ ),
+ ),
+ ] = ArqMode.production
+
+ slack_webhook_url: Annotated[
+ HttpUrl | None,
+ Field(
+ alias="NOTEBURST_SLACK_WEBHOOK_URL",
+ description=(
+ "Webhook URL for sending error messages to a Slack channel."
+ ),
+ ),
+ ] = None
@property
def arq_redis_settings(self) -> RedisSettings:
"""Create a Redis settings instance for arq."""
- # url_parts = urlparse(self.redis_url)
- redis_settings = RedisSettings(
+ return RedisSettings(
host=self.redis_url.host or "localhost",
port=self.redis_url.port or 6379,
database=(
@@ -108,66 +160,115 @@ def arq_redis_settings(self) -> RedisSettings:
else 0
),
)
- return redis_settings
class WorkerConfig(Config):
- identities_path: Path = Field(
- ..., alias="NOTEBURST_WORKER_IDENTITIES_PATH"
- )
- """Path to the configuration file with the pool of Science Platform
- identities available to workers.
- """
-
- queue_name: str = Field("arq:queue", alias="NOTEBURST_WORKER_QUEUE_NAME")
- """Name of the arq queue that the worker processes from."""
-
- identity_lock_redis_url: RedisDsn = Field(
- alias="NOTEBURST_WORKER_LOCK_REDIS_URL",
- # Preferred by mypy over a string default
- default_factory=lambda: RedisDsn("redis://localhost:6379/1"),
- )
-
- job_timeout: int = Field(
- 300,
- alias="NOTEBURST_WORKER_JOB_TIMEOUT",
- description=(
- "The timeout, in seconds, for a job until it is timed out."
+ """Configuration superset for arq worker processes."""
+
+ identities_path: Annotated[
+ Path,
+ Field(
+ alias="NOTEBURST_WORKER_IDENTITIES_PATH",
+ description=(
+ "Path to the configuration file with the pool of Science "
+ "Platform identities available to workers."
+ ),
),
- )
-
- worker_token_lifetime: int = Field(
- 2419200,
- alias="NOTEBURST_WORKER_TOKEN_LIFETIME",
- description="Worker auth token lifetime in seconds.",
- )
-
- worker_token_scopes: str = Field(
- "exec:notebook",
- alias="NOTEBURST_WORKER_TOKEN_SCOPES",
- description=(
- "Worker (nublado2 pod) token scopes as a comma-separated string."
+ ]
+
+ queue_name: Annotated[
+ str,
+ Field(
+ alias="NOTEBURST_WORKER_QUEUE_NAME",
+ description=(
+ "Name of the arq queue that the worker processes from."
+ ),
),
- )
-
- image_selector: JupyterImageSelector = Field(
- JupyterImageSelector.recommended,
- alias="NOTEBURST_WORKER_IMAGE_SELECTOR",
- description="Method for selecting a Jupyter image to run.",
- )
+ ] = "arq:queue"
+
+ identity_lock_redis_url: Annotated[
+ RedisDsn,
+ Field(
+ alias="NOTEBURST_WORKER_LOCK_REDIS_URL",
+ # Preferred by mypy over a string default
+ default_factory=lambda: RedisDsn("redis://localhost:6379/1"),
+ description=(
+ "URL for the redis instance, used by the worker to lock "
+ "JupyterLab user identities to a worker instance."
+ ),
+ ),
+ ]
+
+ job_timeout: Annotated[
+ int,
+ Field(
+ alias="NOTEBURST_WORKER_JOB_TIMEOUT",
+ description=(
+ "The timeout, in seconds, for a job until it is timed out."
+ ),
+ ),
+ ] = 300
+
+ max_concurrent_jobs: Annotated[
+ int,
+ Field(
+ alias="NOTEBURST_WORKER_MAX_CONCURRENT_JOBS",
+ description=(
+ "The maximum number of concurrent jobs a worker can handle. "
+ "This should be equal to less than the number of CPUs on the "
+ "JupyterLab pod."
+ ),
+ ),
+ ] = 3
- image_reference: Optional[str] = Field(
- None,
- alias="NOTEBURST_WORKER_IMAGE_REFERENCE",
- description=(
- "Docker image reference, if NOTEBURST_WORKER_IMAGE_SELECTOR is "
- "``reference``."
+ worker_token_lifetime: Annotated[
+ int,
+ Field(
+ alias="NOTEBURST_WORKER_TOKEN_LIFETIME",
+ description="Worker auth token lifetime in seconds.",
),
- )
+ ] = 2419200
+
+ worker_token_scopes: Annotated[
+ str,
+ Field(
+ alias="NOTEBURST_WORKER_TOKEN_SCOPES",
+ description=(
+ "Worker (nublado pod) token scopes as a comma-separated "
+ "string."
+ ),
+ ),
+ ] = "exec:notebook"
- worker_keepalive: WorkerKeepAliveSetting = Field(
- WorkerKeepAliveSetting.normal, alias="NOTEBURST_WORKER_KEEPALIVE"
- )
+ image_selector: Annotated[
+ JupyterImageSelector,
+ Field(
+ alias="NOTEBURST_WORKER_IMAGE_SELECTOR",
+ description="Method for selecting a Jupyter image to run.",
+ ),
+ ] = JupyterImageSelector.recommended
+
+ image_reference: Annotated[
+ str | None,
+ Field(
+ alias="NOTEBURST_WORKER_IMAGE_REFERENCE",
+ description=(
+ "Docker image reference, if NOTEBURST_WORKER_IMAGE_SELECTOR "
+ "is ``reference``."
+ ),
+ ),
+ ] = None
+
+ worker_keepalive: Annotated[
+ WorkerKeepAliveSetting,
+ Field(
+ alias="NOTEBURST_WORKER_KEEPALIVE",
+ description=(
+ "Keep-alive setting for the worker process. This setting "
+ "must be fast enough to defeat the Nublado pod culler."
+ ),
+ ),
+ ] = WorkerKeepAliveSetting.normal
@property
def aioredlock_redis_config(self) -> list[str]:
diff --git a/src/noteburst/exceptions.py b/src/noteburst/exceptions.py
index c552a00..429c3c1 100644
--- a/src/noteburst/exceptions.py
+++ b/src/noteburst/exceptions.py
@@ -4,7 +4,17 @@
from typing import Self
-__all__ = ["TaskError", "NbexecTaskError"]
+from fastapi import status
+from safir.fastapi import ClientRequestError
+from safir.slack.blockkit import SlackException, SlackMessage, SlackTextField
+
+__all__ = [
+ "TaskError",
+ "NbexecTaskError",
+ "NbexecTaskTimeoutError",
+ "NoteburstClientRequestError",
+ "NoteburstError",
+]
class TaskError(Exception):
@@ -20,10 +30,52 @@ class TaskError(Exception):
@classmethod
def from_exception(cls, exc: Exception) -> Self:
- return cls(f"{cls.task_name} task error\n\n{str(exc)}")
+ return cls(f"{cls.task_name} task error\n\n{exc!s}")
class NbexecTaskError(TaskError):
"""Error related to a notebook execution task (nbexec)."""
task_name = "nbexec"
+
+
+class NbexecTaskTimeoutError(NbexecTaskError):
+ """Error raised when a notebook execution task times out."""
+
+ @classmethod
+ def from_exception(cls, exc: Exception) -> Self:
+ return cls(f"{cls.task_name} timeout error\n\n{exc!s}")
+
+
+class NoteburstClientRequestError(ClientRequestError):
+ """Error related to the API client."""
+
+
+class JobNotFoundError(NoteburstClientRequestError):
+ """Error raised when a notebook execution job is not found."""
+
+ error = "unknown_job"
+ status_code = status.HTTP_404_NOT_FOUND
+
+
+class NoteburstError(SlackException):
+ """Base class for internal Noteburst exceptions on the FastAPI side.
+
+ This exception derives from SlackException so that uncaught internal
+ exceptions are reported to Slack.
+ """
+
+
+class NoteburstJobError(NoteburstError):
+ """Error related to a notebook execution job."""
+
+ def __init__(self, msg: str, *, user: str | None, job_id: str) -> None:
+ super().__init__(msg, user=user)
+ self.job_id = job_id
+
+ def to_slack(self) -> SlackMessage:
+ message = super().to_slack()
+ message.fields.append(
+ SlackTextField(heading="Job ID", text=self.job_id)
+ )
+ return message
diff --git a/src/noteburst/handlers/external.py b/src/noteburst/handlers/external.py
index aadf577..a8ed096 100644
--- a/src/noteburst/handlers/external.py
+++ b/src/noteburst/handlers/external.py
@@ -1,5 +1,7 @@
"""Handlers for the app's external root, ``/noteburst/``."""
+from typing import Annotated
+
from fastapi import APIRouter, Depends
from pydantic import BaseModel, Field
from safir.dependencies.gafaelfawr import auth_logger_dependency
@@ -18,7 +20,7 @@
class Index(BaseModel):
"""Metadata about the application."""
- metadata: SafirMetadata = Field(..., title="Package metadata")
+ metadata: Annotated[SafirMetadata, Field(title="Package metadata")]
@external_router.get(
@@ -29,7 +31,7 @@ class Index(BaseModel):
summary="Application metadata",
)
async def get_index(
- logger: BoundLogger = Depends(auth_logger_dependency),
+ logger: Annotated[BoundLogger, Depends(auth_logger_dependency)],
) -> Index:
"""GET ``/noteburst/`` (the app's external root).
diff --git a/src/noteburst/handlers/v1/handlers.py b/src/noteburst/handlers/v1/handlers.py
index bbacee7..4907b55 100644
--- a/src/noteburst/handlers/v1/handlers.py
+++ b/src/noteburst/handlers/v1/handlers.py
@@ -1,15 +1,24 @@
"""V1 REST API handlers."""
+from typing import Annotated
+
import structlog
from arq.jobs import JobStatus
from fastapi import APIRouter, Depends, Query, Request, Response
-from safir.arq import ArqQueue
+from safir.arq import ArqQueue, JobNotFound
from safir.dependencies.arq import arq_dependency
-from safir.dependencies.gafaelfawr import auth_logger_dependency
+from safir.dependencies.gafaelfawr import (
+ auth_dependency,
+ auth_logger_dependency,
+)
+from safir.models import ErrorLocation, ErrorModel
+from safir.slack.webhook import SlackRouteErrorHandler
+
+from noteburst.exceptions import JobNotFoundError, NoteburstJobError
from .models import NotebookResponse, PostNotebookRequest
-v1_router = APIRouter(tags=["v1"])
+v1_router = APIRouter(tags=["v1"], route_class=SlackRouteErrorHandler)
"""FastAPI router for the /v1/ REST API"""
@@ -25,8 +34,8 @@ async def post_nbexec(
*,
request: Request,
response: Response,
- logger: structlog.BoundLogger = Depends(auth_logger_dependency),
- arq_queue: ArqQueue = Depends(arq_dependency),
+ logger: Annotated[structlog.BoundLogger, Depends(auth_logger_dependency)],
+ arq_queue: Annotated[ArqQueue, Depends(arq_dependency)],
) -> NotebookResponse:
"""Submits a notebook for execution. The notebook is executed
asynchronously via a pool of JupyterLab (Nublado) instances.
@@ -59,6 +68,7 @@ async def post_nbexec(
ipynb=request_data.get_ipynb_as_str(),
kernel_name=request_data.kernel_name,
enable_retry=request_data.enable_retry,
+ timeout=request_data.timeout,
)
logger.info("Finished enqueing an nbexec task", job_id=job_metadata.id)
response_data = await NotebookResponse.from_job_metadata(
@@ -73,6 +83,7 @@ async def post_nbexec(
summary="Get information about a notebook execution job",
response_model=NotebookResponse,
response_model_exclude_none=True,
+ responses={404: {"description": "Not found", "model": ErrorModel}},
)
async def get_nbexec_job(
*,
@@ -94,8 +105,9 @@ async def get_nbexec_job(
"includes the executed notebook and metadata about the run."
),
),
- logger: structlog.BoundLogger = Depends(auth_logger_dependency),
- arq_queue: ArqQueue = Depends(arq_dependency),
+ logger: Annotated[structlog.BoundLogger, Depends(auth_logger_dependency)],
+ user: Annotated[str, Depends(auth_dependency)],
+ arq_queue: Annotated[ArqQueue, Depends(arq_dependency)],
) -> NotebookResponse:
"""Provides information about a notebook execution job, and the result
(if available).
@@ -121,11 +133,16 @@ async def get_nbexec_job(
"""
try:
job_metadata = await arq_queue.get_job_metadata(job_id)
+ except JobNotFound:
+ raise JobNotFoundError(
+ "Job not found", location=ErrorLocation.path, field_path=["job_id"]
+ ) from None
except Exception as e:
- logger.error(
- "Error getting nbexec job metadata", job_id=job_id, exc_info=e
- )
- raise
+ raise NoteburstJobError(
+ "Error getting job metadata",
+ user=user,
+ job_id=job_id,
+ ) from e
logger.debug(
"Got nbexec job metadata",
job_id=job_id,
@@ -136,11 +153,18 @@ async def get_nbexec_job(
if result and job_metadata.status == JobStatus.complete:
try:
job_result = await arq_queue.get_job_result(job_id)
+ except JobNotFound:
+ raise JobNotFoundError(
+ "Job not found",
+ location=ErrorLocation.path,
+ field_path=["job_id"],
+ ) from None
except Exception as e:
- logger.error(
- "Error getting nbexec job result", job_id=job_id, exc_info=e
- )
- raise
+ raise NoteburstJobError(
+ "Error getting nbexec job result",
+ user=user,
+ job_id=job_id,
+ ) from e
logger.debug(
"Got nbexec job result",
job_id=job_id,
diff --git a/src/noteburst/handlers/v1/models.py b/src/noteburst/handlers/v1/models.py
index 020aad0..306af48 100644
--- a/src/noteburst/handlers/v1/models.py
+++ b/src/noteburst/handlers/v1/models.py
@@ -3,18 +3,19 @@
from __future__ import annotations
import json
-from datetime import datetime
-from typing import Any, Optional, Union
+from datetime import datetime, timedelta
+from enum import Enum
+from typing import Annotated, Any
+import rubin.nublado.client.models as nc_models
from arq.jobs import JobStatus
from fastapi import Request
from pydantic import AnyHttpUrl, BaseModel, Field
+from rubin.nublado.client.models._extension import NotebookExecutionErrorModel
from safir.arq import JobMetadata, JobResult
+from safir.pydantic import HumanTimedelta
-from noteburst.jupyterclient.jupyterlab import (
- NotebookExecutionErrorModel,
- NotebookExecutionResult,
-)
+from noteburst.exceptions import NbexecTaskError, NbexecTaskTimeoutError
kernel_name_field = Field(
"LSST",
@@ -31,14 +32,14 @@
class NotebookError(BaseModel):
"""Information about an exception that occurred during notebook exec."""
- name: str = Field(description="The name of the exception.")
- message: str = Field(description="The exception's message.")
+ name: Annotated[str, Field(description="The name of the exception.")]
+ message: Annotated[str, Field(description="The exception's message.")]
@classmethod
def from_nbexec_error(
cls, error: NotebookExecutionErrorModel
) -> NotebookError:
- """Create a NotebookError from a NotebookExecutionErrorModel, which
+ """Create a NotebookError from NotebookExecutionErrorModel, which
is the result of execution in ``/user/:username/rubin/execute``.
"""
return cls(
@@ -47,61 +48,125 @@ def from_nbexec_error(
)
+class NoteburstErrorCodes(Enum):
+ """Error codes for Noteburst errors."""
+
+ timeout = "timeout"
+ """The notebook execution timed out."""
+
+ jupyter_error = "jupyter_error"
+ """An error occurred contacting the Jupyter server."""
+
+ unknown = "unknown"
+ """An unknown error occurred."""
+
+
+class NoteburstExecutionError(BaseModel):
+ """Information about an exception that occurred during noteburst's
+ execution of a notebook (other than an exception raised in the notebook
+ itself).
+ """
+
+ code: NoteburstErrorCodes = Field(
+ description="The reference code of the error."
+ )
+
+ message: str | None = Field(
+ None, description="Additional information about the exception."
+ )
+
+
class NotebookResponse(BaseModel):
"""Information about a notebook execution job, possibly including the
result and source notebooks.
"""
- job_id: str = Field(title="The job ID")
+ job_id: Annotated[str, Field(title="The job ID")]
- kernel_name: str = kernel_name_field
+ kernel_name: Annotated[str, kernel_name_field]
- enqueue_time: datetime = Field(
- title="Time when the job was added to the queue (UTC)"
- )
+ enqueue_time: Annotated[
+ datetime, Field(title="Time when the job was added to the queue (UTC)")
+ ]
- status: JobStatus = Field(
- title="The current status of the notebook execution job"
- )
+ status: Annotated[
+ JobStatus,
+ Field(title="The current status of the notebook execution job"),
+ ]
- self_url: AnyHttpUrl = Field(title="The URL of this resource")
+ self_url: Annotated[AnyHttpUrl, Field(title="The URL of this resource")]
- source: Optional[str] = Field(
- None,
- title="The content of the source ipynb file (JSON-encoded string)",
- description="This field is null unless the source is requested.",
- )
+ source: Annotated[
+ str | None,
+ Field(
+ title="The content of the source ipynb file (JSON-encoded string)",
+ description="This field is null unless the source is requested.",
+ ),
+ ] = None
- start_time: Optional[datetime] = Field(
- None,
- title="Time when the notebook execution started (UTC)",
- description="This field is present if the result is available.",
- )
+ start_time: Annotated[
+ datetime | None,
+ Field(
+ title="Time when the notebook execution started (UTC)",
+ description="This field is present if the result is available.",
+ ),
+ ] = None
- finish_time: Optional[datetime] = Field(
- None,
- title="Time when the notebook execution completed (UTC)",
- description="This field is present only if the result is available.",
- )
+ finish_time: Annotated[
+ datetime | None,
+ Field(
+ title="Time when the notebook execution completed (UTC)",
+ description=(
+ "This field is present only if the result is available."
+ ),
+ ),
+ ] = None
- success: Optional[bool] = Field(
- None,
- title="Whether the execution was successful or not",
- description="This field is present if the result is available.",
- )
+ success: Annotated[
+ bool | None,
+ Field(
+ title="Whether the execution was successful or not",
+ description="This field is present if the result is available.",
+ ),
+ ] = None
- ipynb: Optional[str] = Field(
- None,
- title="The contents of the executed Jupyter notebook",
- description="The ipynb is a JSON-encoded string. This field is "
- "present if the result is available.",
- )
+ error: Annotated[
+ NoteburstExecutionError | None,
+ Field(
+ description=(
+ "An error occurred during notebook execution, other than an "
+ "exception in the notebook itself. This field is null if an "
+ "error did not occur."
+ )
+ ),
+ ] = None
- ipynb_error: Optional[NotebookError] = Field(
- None,
- title="The error that occurred during notebook execution",
- description="This field is null if an exeception did not occur.",
- )
+ ipynb: Annotated[
+ str | None,
+ Field(
+ title="The contents of the executed Jupyter notebook",
+ description="The ipynb is a JSON-encoded string. This field is "
+ "present if the result is available.",
+ ),
+ ] = None
+
+ ipynb_error: Annotated[
+ NotebookError | None,
+ Field(
+ None,
+ title="The error that occurred during notebook execution",
+ description="This field is null if an exeception did not occur.",
+ ),
+ ] = None
+
+ timeout: Annotated[
+ float | None,
+ Field(
+ None,
+ title="The job's timeout in seconds",
+ description="This field is null if a timeout was not set.",
+ ),
+ ] = None
@classmethod
async def from_job_metadata(
@@ -110,23 +175,46 @@ async def from_job_metadata(
job: JobMetadata,
request: Request,
include_source: bool = False,
- job_result: Optional[JobResult] = None,
+ job_result: JobResult | None = None,
) -> NotebookResponse:
+ """Create a NotebookResponse from a job."""
+ # When a job is a "success" it means that the arq worker didn't raise
+ # an exception, so we can expect an ipynb result. However the ipynb
+ # might have still raised an exception which is part of
+ # nbexec_result.error and we want to pass that back to the user.
if job_result is not None and job_result.success:
- print("job_result.result")
- print(type(job_result.result))
- print(job_result.result)
- nbexec_result = NotebookExecutionResult.model_validate_json(
+ res = nc_models.NotebookExecutionResult.model_validate_json(
job_result.result
)
- ipynb = nbexec_result.notebook
- if nbexec_result.error:
- error = NotebookError.from_nbexec_error(nbexec_result.error)
+ ipynb = res.notebook
+ if res.error:
+ ipynb_error = NotebookError.from_nbexec_error(res.error)
else:
- error = None
+ ipynb_error = None
else:
ipynb = None
- error = None
+ ipynb_error = None
+
+ # In this case the job is complete but failed (an exception was raised)
+ # so we want to pass the exception back to the user.
+ noteburst_error = None
+ if job_result and not job_result.success:
+ if e := job_result.result:
+ if isinstance(job_result.result, NbexecTaskTimeoutError):
+ noteburst_error = NoteburstExecutionError(
+ code=NoteburstErrorCodes.timeout,
+ message=str(e).strip(),
+ )
+ elif isinstance(job_result.result, NbexecTaskError):
+ noteburst_error = NoteburstExecutionError(
+ code=NoteburstErrorCodes.jupyter_error,
+ message=str(e).strip(),
+ )
+ elif isinstance(job_result.result, Exception):
+ noteburst_error = NoteburstExecutionError(
+ code=NoteburstErrorCodes.unknown,
+ message=str(e).strip(),
+ )
return cls(
job_id=job.id,
@@ -138,38 +226,56 @@ async def from_job_metadata(
start_time=job_result.start_time if job_result else None,
finish_time=job_result.finish_time if job_result else None,
success=job_result.success if job_result else None,
+ error=noteburst_error,
ipynb=ipynb,
- ipynb_error=error,
+ ipynb_error=ipynb_error,
+ timeout=job.kwargs["timeout"].total_seconds(),
)
class PostNotebookRequest(BaseModel):
"""The ``POST /notebooks/`` request body."""
- ipynb: Union[str, dict[str, Any]] = Field(
- ...,
- title="The contents of a Jupyter notebook",
- description="If a string, the content is parsed as JSON. "
- "Alternatively, the content can be submitted pre-parsed as "
- "an object.",
- )
+ ipynb: Annotated[
+ str | dict[str, Any],
+ Field(
+ title="The contents of a Jupyter notebook",
+ description="If a string, the content is parsed as JSON. "
+ "Alternatively, the content can be submitted pre-parsed as "
+ "an object.",
+ ),
+ ]
- kernel_name: str = kernel_name_field
+ kernel_name: Annotated[str, kernel_name_field]
- enable_retry: bool = Field(
- True,
- title="Enable retries on failures",
+ timeout: HumanTimedelta = Field(
+ default_factory=lambda: timedelta(seconds=300),
+ title="Timeout for notebook execution.",
description=(
- "If true (default), noteburst will retry notebook "
- "execution if the notebook fails, with an increasing back-off "
- "time between tries. This is useful for dealing with transient "
- "issues. However, if you are using Noteburst for continuous "
- "integration of notebooks, disabling retries provides faster "
- "feedback."
+ "The timeout can either be written as a number in seconds or as a "
+ "human-readable duration string. For example, '5m' is 5 minutes, "
+ "'1h' is 1 hour, '1d' is 1 day. If the notebook execution does "
+ "not complete within this time, the job is marked as failed."
),
)
+ enable_retry: Annotated[
+ bool,
+ Field(
+ title="Enable retries on failures",
+ description=(
+ "If true (default), noteburst will retry notebook "
+ "execution if the notebook fails, with an increasing back-off "
+ "time between tries. This is useful for dealing with "
+ "transient issues. However, if you are using Noteburst for "
+ "continuous integration of notebooks, disabling retries "
+ "provides faster feedback."
+ ),
+ ),
+ ] = True
+
def get_ipynb_as_str(self) -> str:
+ """Get the ipynb as a JSON-encoded string."""
if isinstance(self.ipynb, str):
return self.ipynb
else:
diff --git a/src/noteburst/jupyterclient/jupyterlab.py b/src/noteburst/jupyterclient/jupyterlab.py
deleted file mode 100644
index 7d0a5f0..0000000
--- a/src/noteburst/jupyterclient/jupyterlab.py
+++ /dev/null
@@ -1,766 +0,0 @@
-"""Client for JupyterLab through the JupyterHub."""
-
-from __future__ import annotations
-
-import asyncio
-import contextlib
-import datetime
-import json
-import random
-import string
-from dataclasses import dataclass
-from typing import Any, AsyncGenerator, AsyncIterator, Optional
-from urllib.parse import urljoin, urlparse
-from uuid import uuid4
-
-import httpx
-import websockets
-from pydantic import BaseModel, Field
-from structlog import BoundLogger
-from websockets.client import WebSocketClientProtocol
-from websockets.exceptions import WebSocketException
-from websockets.typing import Data as WebsocketData
-
-from noteburst.config import JupyterImageSelector
-from noteburst.config import config as noteburst_config
-
-from .labcontroller import JupyterImage, LabControllerClient
-from .user import AuthenticatedUser
-
-__all__ = [
- "SpawnProgressMessage",
- "JupyterSpawnProgress",
- "JupyterLabSession",
- "JupyterConfig",
- "JupyterError",
- "JupyterLabSessionError",
- "JupyterClient",
-]
-
-
-@dataclass(frozen=True)
-class SpawnProgressMessage:
- """A progress message from JupyterLab spawning."""
-
- progress: int
- """Percentage progress on spawning."""
-
- message: str
- """A progress message."""
-
- ready: bool
- """Whether the server is ready."""
-
-
-class JupyterSpawnProgress:
- """Provides status and polling of lab spawn progress.
-
- This wraps an ongoing call to the progress API, which is an EventStream
- API that provides status messages for a spawning lab.
- """
-
- def __init__(self, response: httpx.Response, logger: BoundLogger) -> None:
- self._response = response
- self._logger = logger
- self._start = datetime.datetime.now(tz=datetime.timezone.utc)
-
- async def __aiter__(self) -> AsyncIterator[SpawnProgressMessage]:
- """Iterate over spawn progress events."""
- prefix = "data:"
- prefix_length = len(prefix)
-
- async for line in self._response.aiter_lines():
- if not line.startswith(prefix):
- continue
- raw_event = line[prefix_length:].strip()
-
- # Parse the valid event
- try:
- event_dict = json.loads(raw_event)
- event = SpawnProgressMessage(
- progress=event_dict["progress"],
- message=event_dict["message"],
- ready=event_dict.get("ready", False),
- )
- except Exception as e:
- msg = f"Ignoring invalid progress event: {raw_event}: {str(e)}"
- self._logger.warning(
- msg, raw_event=raw_event, exception=str(e)
- )
- continue
-
- # Log and yield the event
- now = datetime.datetime.now(tz=datetime.timezone.utc)
- elapsed = int((now - self._start).total_seconds())
- if event.ready:
- status = "complete"
- else:
- status = "in progress"
- self._logger.info(
- "Spawning",
- status=status,
- elapsed=elapsed,
- details=event.message,
- )
- yield event
-
-
-@dataclass
-class WebSocketMessageOutput:
- """The incremental output from a JupyterLab websocket."""
-
- content: str
- """The content from the websocket message."""
-
- done: bool
- """This flag is `True` if there are no further messages."""
-
-
-@dataclass(frozen=True)
-class JupyterLabSession:
- """Represents an open session with a JupyterLab.
-
- This holds the information a client needs to talk to JupyterLab in order to
- execute code.
- """
-
- username: str
- session_id: str
- kernel_id: str
- websocket: WebSocketClientProtocol
- logger: BoundLogger
-
- async def run_python(self, code: str) -> str:
- """Run a Python code in the JupyterLab kernel."""
- msg_id = uuid4().hex
- msg = {
- "header": {
- "username": self.username,
- "version": "5.0",
- "session": self.session_id,
- "msg_id": msg_id,
- "msg_type": "execute_request",
- },
- "parent_header": {},
- "channel": "shell",
- "content": {
- "code": code,
- "silent": False,
- "store_history": False,
- "user_expressions": {},
- "allow_stdin": False,
- },
- "metadata": {},
- "buffers": {},
- }
-
- await self.websocket.send(json.dumps(msg))
-
- result = ""
- async for message in self.websocket:
- try:
- parsed_message = await self._process_run_python_message(
- message, msg_id, code
- )
- result += parsed_message.content
- if parsed_message.done:
- break
- except CodeExecutionError as e:
- if result:
- e.result = result
- raise
-
- return result
-
- async def _process_run_python_message(
- self, raw_message: WebsocketData, msg_id: str, code: str
- ) -> WebSocketMessageOutput:
- """Process an individual message received from the websocket,
- initiated from `run_python`.
-
- This method returns incremental fragments of the result string. If
- the message is an ``execute_reply`` with status of ``ok``, then this
- method toggles the ``done`` attribute of the returned
- `WebSocketMessageOutput` to done.
- """
- if isinstance(raw_message, bytes):
- raw_text = raw_message.decode("utf-8")
- else:
- raw_text = raw_message
- response_data = json.loads(raw_text)
-
- self.logger.debug(f"Received kernel message: {response_data}")
- msg_type = response_data["msg_type"]
-
- if response_data.get("parent_header", {}).get("msg_id") != msg_id:
- # Ignore messages not intended for us. The web socket is
- # rather chatty with broadcast status messages.
- return WebSocketMessageOutput(content="", done=False)
- elif msg_type == "error":
- error = "".join(response_data["content"]["traceback"])
- raise CodeExecutionError(
- username=self.username, code=code, error=error
- )
- elif msg_type == "stream":
- return WebSocketMessageOutput(
- content=response_data["content"]["text"], done=False
- )
- elif msg_type == "execute_reply":
- status = response_data["content"]["status"]
- if status == "ok":
- return WebSocketMessageOutput(content="", done=True)
- else:
- raise CodeExecutionError(
- username=self.username, code=code, status=status
- )
- elif msg_type == "status":
- # Ignore status messages
- return WebSocketMessageOutput(content="", done=False)
- elif msg_type == "execute_input":
- # Ignore execute input messages
- return WebSocketMessageOutput(content="", done=False)
- else:
- self.logger.warning(
- "Got a unexpected websocket msg_type",
- websocket_payload=response_data,
- )
- return WebSocketMessageOutput(content="", done=False)
-
-
-@dataclass
-class JupyterConfig:
- """Configurations for talking to JupyterHub and spawning a JupyterLab
- session.
- """
-
- image_selector: JupyterImageSelector
- """Method for selecting the JupyterLab image."""
-
- url_prefix: str = "/nb/"
- """URL path prefix for the JupyterHub service."""
-
- image_reference: Optional[str] = None
- """Docker reference to the JupyterLab image to spawn.
-
- May be null if ``image_selector`` is is not
- `JupyterImageSelector.reference`.
- """
-
- image_size: str = "Large"
- """Size of the image to spawn (must be one of the sizes permitted by
- nublado2).
- """
-
-
-class JupyterError(Exception):
- """An error related to Jupyter client usage."""
-
- @classmethod
- def from_response(
- cls, username: str, response: httpx.Response
- ) -> JupyterError:
- return cls(
- url=str(response.url),
- username=username,
- status=response.status_code,
- reason=response.reason_phrase,
- method=response.request.method,
- body=response.text,
- )
-
- @classmethod
- async def from_stream(
- cls, username: str, stream: httpx.Response
- ) -> JupyterError:
- body_bytes = await stream.aread()
- return cls(
- url=str(stream.url),
- username=username,
- status=stream.status_code,
- reason=stream.reason_phrase,
- method=stream.request.method,
- body=body_bytes.decode("utf-8"),
- )
-
- def __init__(
- self,
- *,
- url: str,
- username: str,
- status: int,
- reason: Optional[str],
- method: str,
- body: Optional[str] = None,
- ) -> None:
- self.url = url
- self.status = status
- self.reason = reason
- self.method = method
- self.body = body
- self.username = username
- self.timestamp = datetime.datetime.now(tz=datetime.timezone.utc)
- super().__init__(f"Status {status} from {method} {url}")
-
- def __str__(self) -> str:
- result = (
- f"{self.username}: status {self.status} ({self.reason}) from"
- f" {self.method} {self.url}"
- )
- return result
-
-
-class JupyterLabSessionError(Exception):
- """An error related to a JupyterLab websocket session."""
-
- def __init__(self, message: str, *, username: str) -> None:
- self.username = username
- super().__init__(message)
-
- @classmethod
- def from_exception(
- cls, *, username: str, exception: Exception
- ) -> JupyterLabSessionError:
- return cls(str(exception), username=username)
-
-
-class CodeExecutionError(Exception):
- """An error related to code execution in a JupyterLab session."""
-
- def __init__(
- self,
- *,
- username: str,
- code: str,
- code_type: str = "code",
- error: Optional[str] = None,
- status: Optional[str] = None,
- result: Optional[str] = None,
- ) -> None:
- self.username = username
- self.code = code
- self.code_type = code_type
- self.error = error
- self.status = status
- self.result = result
- super().__init__("Code execution failed")
-
- def __str__(self) -> str:
- message = (
- f"{self.username}: running {self.code_type} "
- f"'{self.code}' failed"
- )
-
- message += f"\nError: {self.error}"
-
- if self.result:
- message = f"{self.result}\n{message}"
-
- return message
-
-
-class NotebookExecutionErrorModel(BaseModel):
- """The error from the /user/:username/rubin/execute endpoint."""
-
- traceback: str = Field(description="The exeception traceback.")
-
- ename: str = Field(description="The exception name.")
-
- evalue: str = Field(description="The exception value.")
-
- err_msg: str = Field(description="The exception message.")
-
-
-class NotebookExecutionResult(BaseModel):
- """The result of the /user/:username/rubin/execute endpoint."""
-
- notebook: str = Field(
- description="The notebook that was executed, as a JSON string."
- )
-
- resources: dict[str, Any] = Field(
- description=(
- "The resources used to execute the notebook, as a JSON string."
- )
- )
-
- error: NotebookExecutionErrorModel | None = Field(
- None, description="The error that occurred during execution."
- )
-
-
-class JupyterClient:
- """A client for JupyterLab, via JupyterHub.
-
- This client can optionally be used as a async Python context manager.
- If not, remember to call the close() method to clean up the HTTP
- connections
-
- Parameters
- ----------
- user : `noteburst.jupyterclient.user.AuthenticatedUser`
- The user's information.
- logger : structlog.BoundLogger
- A logger instance that may be associated with existing context.
- config : JupyterConfig
- Configuration for the JupyterLab image to spawn.
- """
-
- def __init__(
- self,
- *,
- user: AuthenticatedUser,
- logger: BoundLogger,
- config: JupyterConfig,
- ) -> None:
- self.user = user
- self.logger = logger
- self.config = config
-
- self.jupyter_url = urljoin(
- str(noteburst_config.environment_url), self.config.url_prefix
- )
-
- self._http_client: Optional[httpx.AsyncClient] = None
- self._lab_controller_client: Optional[LabControllerClient] = None
- self._common_headers: dict[str, str] # set and reset in the context
-
- @property
- def http_client(self) -> httpx.AsyncClient:
- """The HTTPX client instance associated with the Jupyter session.."""
- if self._http_client is None:
- self._open_clients()
- assert self._http_client is not None
- return self._http_client
-
- @property
- def lab_controller(self) -> LabControllerClient:
- """The Jupyter Lab Controller client, only available in the
- JupyterClient context.
- """
- if self._lab_controller_client is None:
- self._open_clients()
- assert self._lab_controller_client is not None
- return self._lab_controller_client
-
- async def __aenter__(self) -> JupyterClient:
- self._open_clients()
- return self
-
- def _open_clients(self) -> None:
- if (self._http_client is not None) or (
- self._lab_controller_client is not None
- ):
- raise RuntimeError(
- "JupyterClient is already open. Call close() before "
- "re-opening?"
- )
-
- xsrf_token = "".join(
- random.choices(string.ascii_uppercase + string.digits, k=16)
- )
- headers = {
- "x-xsrftoken": xsrf_token,
- "Authorization": f"Bearer {self.user.token}",
- }
- self._common_headers = headers
- cookies = {"_xsrf": xsrf_token}
-
- self._http_client = httpx.AsyncClient(
- headers=headers,
- cookies=cookies,
- follow_redirects=True,
- timeout=30.0, # default is 5, but Hub can be slow
- )
-
- # Create a LabController client
- # We also send the XSRF token to Lab Controller because of how we're
- # sharing the session, but that shouldn't matter.
- assert noteburst_config.gafaelfawr_token
- self._lab_controller_client = LabControllerClient(
- http_client=self.http_client,
- token=noteburst_config.gafaelfawr_token.get_secret_value(),
- url_prefix=noteburst_config.nublado_controller_path_prefix,
- )
-
- async def __aexit__(self, *exc_info: Any) -> None:
- await self.close()
-
- async def close(self) -> None:
- """Manually close the client.
-
- Do not use this method for manually closing the Jupyter client when
- using JupyterClient as an async context manager. The client is
- closed automatically.
- """
- self._lab_controller_client = None
-
- await self.http_client.aclose()
- self._http_client = None
- self._common_headers = {}
-
- def url_for(self, path: str) -> str:
- """Create a URL relative to the jupyter_url."""
- if self.jupyter_url.endswith("/"):
- return f"{self.jupyter_url}{path}"
- else:
- return f"{self.jupyter_url}/{path}"
-
- def url_for_websocket(self, path: str) -> str:
- """Create a wss:// URL relative to the jupyter_url."""
- http_url = self.url_for(path)
- return urlparse(http_url)._replace(scheme="wss").geturl()
-
- async def log_into_hub(self) -> None:
- """Log into JupyterHub or raise a JupyterError."""
- self.logger.debug("Logging into JupyterHub")
- r = await self.http_client.get(
- self.url_for("hub/login"), follow_redirects=False
- )
- # JupyterHub returns a 302 redirect to the login page on success,
- # but we don't want to follow that redirect. This request is just
- # to set cookies.
- if r.status_code >= 400:
- raise JupyterError.from_response(self.user.username, r)
-
- async def log_into_lab(self) -> None:
- """Log into JupyterLab or raise a JupyterError."""
- self.logger.debug("Logging into JupyterLab")
- r = await self.http_client.get(
- self.url_for(f"user/{self.user.username}/lab")
- )
- if r.status_code != 200:
- raise JupyterError.from_response(self.user.username, r)
-
- async def spawn_lab(self) -> JupyterImage:
- """Spawn a JupyterLab pod."""
- spawn_url = self.url_for("hub/spawn")
-
- # Retrieving the spawn page before POSTing to it appears to trigger
- # some necessary internal state construction (and also more accurately
- # simulates a user interaction). See DM-23864.
- _ = await self.http_client.get(spawn_url)
-
- # POST the options form to the spawn page. This should redirect to
- # the spawn-pending page, which will return a 200.
- image = await self._get_spawn_image()
- data = self._build_jupyter_spawn_form(image)
- r = await self.http_client.post(spawn_url, data=data)
- if r.status_code != 200:
- raise JupyterError.from_response(self.user.username, r)
-
- # Return information about the image spawned so that we can use it to
- # annotate timers and get it into error reports.
- return image
-
- async def spawn_progress(self) -> AsyncIterator[SpawnProgressMessage]:
- """Monitor lab spawn progress.
-
- This is an EventStream API, which provides a stream of events until
- the lab is spawned or the spawn fails.
- """
- progress_url = self.url_for(
- f"hub/api/users/{self.user.username}/server/progress"
- )
- referer_url = self.url_for("hub/home")
- headers = {"Referer": referer_url}
- while True:
- async with self.http_client.stream(
- "GET", progress_url, headers=headers
- ) as response_stream:
- if response_stream.status_code != 200:
- raise await JupyterError.from_stream(
- self.user.username, response_stream
- )
- progress = JupyterSpawnProgress(response_stream, self.logger)
- async for message in progress:
- yield message
-
- # Sometimes we get only the initial request message and then
- # the progress API immediately closes the connection. If that
- # happens, try reconnecting to the progress stream after a
- # short delay.
- if message.progress > 0:
- break
- await asyncio.sleep(1)
- self.logger.info("Retrying spawn progress request")
-
- async def _get_spawn_image(self) -> JupyterImage:
- """Determine what image to spawn."""
- if self.config.image_selector == JupyterImageSelector.recommended:
- image = await self.lab_controller.get_recommended()
- elif self.config.image_selector == JupyterImageSelector.weekly:
- image = await self.lab_controller.get_latest_weekly()
- elif self.config.image_selector == JupyterImageSelector.reference:
- assert self.config.image_reference
- image = await self.lab_controller.get_by_reference(
- self.config.image_reference
- )
- else:
- # This should be prevented by the model as long as we don't add a
- # new image class without adding the corresponding condition.
- raise ValueError(
- f"Invalid image_selector {self.config.image_selector}"
- )
- return image
-
- def _build_jupyter_spawn_form(self, image: JupyterImage) -> dict[str, Any]:
- """Construct the form to submit to the JupyterHub spawning page."""
- return {
- "image_list": [image.reference],
- "image_dropdown": [image.reference],
- "size": self.config.image_size,
- }
-
- async def stop_lab(self) -> None:
- """Stop the JupyterLab server."""
- if await self.is_lab_stopped():
- self.logger.info("Lab is already stopped")
- return
- user = self.user.username
- server_url = self.url_for(f"hub/api/users/{user}/server")
- referer_url = self.url_for("hub/home")
- headers = {"Referer": referer_url}
- r = await self.http_client.delete(server_url, headers=headers)
- if r.status_code not in [200, 202, 204]:
- raise JupyterError.from_response(self.user.username, r)
-
- async def is_lab_stopped(self, final: bool = False) -> bool:
- """Determine if the lab is fully stopped.
-
- Parameters
- ----------
- final : `bool`
- The last attempt, so log some additional information if the lab
- still isn't gone.
- """
- user_url = self.url_for(f"hub/api/users/{self.user.username}")
- referer_url = self.url_for("hub/home")
- headers = {"Referer": referer_url}
- r = await self.http_client.get(user_url, headers=headers)
- if r.status_code != 200:
- raise JupyterError.from_response(self.user.username, r)
- data = r.json()
- result = data["servers"] == {}
- if final and not result:
- msg = f'Server data still shows running lab: {data["servers"]}'
- self.logger.warning(msg)
- return result
-
- @contextlib.asynccontextmanager
- async def open_lab_session(
- self, notebook_name: Optional[str] = None, *, kernel_name: str = "LSST"
- ) -> AsyncGenerator[JupyterLabSession, None]:
- """Open a JupyterLab session.
-
- Send and receive messages from JupyterLab using the ``websocket``
- property on `JupyterLabSession`.
- """
- session_url = self.url_for(f"user/{self.user.username}/api/sessions")
- session_type = "notebook" if notebook_name else "console"
- body = {
- "kernel": {"name": kernel_name},
- "name": notebook_name or "(no notebook)",
- "path": notebook_name if notebook_name else uuid4().hex,
- "type": session_type,
- }
- r = await self.http_client.post(session_url, json=body)
- if r.status_code != 201:
- raise JupyterError.from_response(self.user.username, r)
- session_resource = r.json()
-
- kernel_id = session_resource["kernel"]["id"]
- http_channels_uri = self.url_for(
- f"user/{self.user.username}/api/kernels/{kernel_id}/channels"
- )
- wss_channels_uri = self.url_for_websocket(
- f"user/{self.user.username}/api/kernels/{kernel_id}/channels"
- )
-
- # Generate a mock request and copy its headers / cookies over to the
- # websocket connection.
- mock_request = self.http_client.build_request("GET", http_channels_uri)
- copied_headers = ["x-xsrftoken", "authorization", "cookie"]
- websocket_headers = {
- header: mock_request.headers[header] for header in copied_headers
- }
-
- session_id: Optional[str] = None # will be set if a session is opened
- self.logger.debug("Trying to create websocket connection")
- try:
- # An alternative to the async context it to use connect in an
- # infinite async generator that can automatically reconnect
- # if the connection is dropped. This could be good for very
- # long lived clients
- # https://websockets.readthedocs.io/en/stable/reference/client.html#using-a-connection
- async with websockets.connect(
- wss_channels_uri, extra_headers=websocket_headers
- ) as websocket:
- self.logger.info("Created websocket connection")
- jupyter_lab_session = JupyterLabSession(
- username=self.user.username,
- session_id=session_resource["id"],
- kernel_id=kernel_id,
- websocket=websocket,
- logger=self.logger,
- )
- session_id = jupyter_lab_session.session_id
- yield jupyter_lab_session
- except WebSocketException as e:
- raise JupyterLabSessionError.from_exception(
- username=self.user.username, exception=e
- )
- finally:
- if session_id:
- session_id_url = self.url_for(
- f"user/{self.user.username}/api/sessions/{session_id}"
- )
- r = await self.http_client.delete(session_id_url)
- if r.status_code != 204:
- raise JupyterError.from_response(self.user.username, r)
-
- async def execute_notebook(
- self, notebook: dict[str, Any], kernel_name: str = "LSST"
- ) -> NotebookExecutionResult:
- """Execute a Jupyter notebook through the JupyterLab Notebook execution
- extension.
-
- Parameters
- ----------
- notebook : dict
- A Jupyter Notebook, parsed from its JSON form.
-
- Returns
- -------
- notebook : dict
- The executed Jupyter Notebook.
-
- Raises
- ------
- NotebookExecutionResult
- Raised if there is an error interacting with the JupyterLab
- Notebook execution extension.
- """
- exec_url = self.url_for(f"user/{self.user.username}/rubin/execution")
- r = await self.http_client.post(
- exec_url,
- content=json.dumps(notebook).encode("utf-8"),
- )
- if r.status_code != 200:
- raise JupyterError.from_response(self.user.username, r)
- self.logger.debug("Got response from /rubin/execution", text=r.text)
-
- return NotebookExecutionResult.model_validate_json(r.text)
-
- async def get_jupyterlab_env(self) -> dict[str, Any]:
- """Get metadata from the JupyterLab environment endpoint.
-
- Uses the ``/user/:username/rubin/environment`` extension endpoint.
- """
- environment_url = self.url_for(
- f"user/{self.user.username}/rubin/environment"
- )
- r = await self.http_client.get(environment_url)
- if r.status_code != 200:
- raise JupyterError.from_response(self.user.username, r)
- env_data = r.json()
- return env_data
diff --git a/src/noteburst/jupyterclient/labcontroller.py b/src/noteburst/jupyterclient/labcontroller.py
deleted file mode 100644
index 4cd6bfb..0000000
--- a/src/noteburst/jupyterclient/labcontroller.py
+++ /dev/null
@@ -1,208 +0,0 @@
-"""Client for the JupyterLab Controller service."""
-
-from __future__ import annotations
-
-from typing import Optional
-from urllib.parse import urljoin
-
-import httpx
-from pydantic import BaseModel, Field
-
-from noteburst.config import config
-
-
-class JupyterImage(BaseModel):
- """A model for a JupyterLab image in a `LabControllerImages` resource."""
-
- reference: str = Field(
- ...,
- examples=["lighthouse.ceres/library/sketchbook:latest_daily"],
- title="Full Docker registry path for lab image",
- description="cf. https://docs.docker.com/registry/introduction/",
- )
-
- name: str = Field(
- ...,
- examples=["Latest Daily (Daily 2077_10_23)"],
- title="Human-readable version of image tag",
- )
-
- digest: Optional[str] = Field(
- None,
- examples=[
- "sha256:e693782192ecef4f7846ad2b21"
- "b1574682e700747f94c5a256b5731331a2eec2"
- ],
- title="unique digest of image contents",
- )
-
- tag: str = Field(
- title="Image tag",
- )
-
- size: Optional[int] = Field(
- None,
- examples=[8675309],
- title="Size in bytes of image. None if image size is unknown",
- )
- prepulled: bool = Field(
- False,
- examples=[False],
- title="Whether image is prepulled to all eligible nodes",
- )
-
-
-def underscore_to_dash(x: str) -> str:
- return x.replace("_", "-")
-
-
-class LabControllerImages(BaseModel):
- """A model for the ``GET /nublado/spawner/v1/images`` response."""
-
- recommended: Optional[JupyterImage] = Field(
- None, title="The recommended image"
- )
-
- latest_weekly: Optional[JupyterImage] = Field(
- None, title="The latest weekly release image"
- )
-
- latest_daily: Optional[JupyterImage] = Field(
- None, title="The latest daily release image"
- )
-
- latest_release: Optional[JupyterImage] = Field(
- None, title="The latest release image"
- )
-
- all: list[JupyterImage] = Field(default_factory=list, title="All images")
-
- def get_by_reference(self, reference: str) -> Optional[JupyterImage]:
- """Get the JupyterImage with a corresponding reference.
-
- Parameters
- ----------
- reference
- The image reference.
-
- Returns
- -------
- JupyterImage or None
- Returns the JupyterImage if found, None otherwise.
- """
- for image in self.all:
- if reference == image.reference:
- return image
-
- return None
-
- class Config:
- allow_population_by_field_name = True
- alias_generator = underscore_to_dash
-
-
-class LabControllerError(Exception):
- """Unable to get image information from the JupyterLab Controller."""
-
-
-class LabControllerClient:
- """A client for the JupyterLab Controller service.
-
- The JupyterLab Controller provides the listing of available DockerImages
- for JupyterLab pods, and provides info about what image is "recommended"
- or is the latest weekly or daily image.
-
- Parameters
- ----------
- http_client
- The HTTPX async client.
- token
- The Gafaelfawr token.
- url_prefix
- The URL path prefix for Nublado JupyterLab Controller service.
- """
-
- def __init__(
- self, *, http_client: httpx.AsyncClient, token: str, url_prefix: str
- ) -> None:
- self._http_client = http_client
- self._token = token
- self._url_prefix = url_prefix
-
- async def get_latest_weekly(self) -> JupyterImage:
- """Image for the latest weekly version.
-
- Returns
- -------
- JupyterImage
- The corresponding image.
-
- Raises
- ------
- LabControllerError
- Some error occurred talking to JupyterLab Controller or does
- not have any weekly images.
- """
- images = await self._get_images()
- image = images.latest_weekly
- if image is None:
- raise LabControllerError("No weekly image found.")
- return image
-
- async def get_recommended(self) -> JupyterImage:
- """Image for the latest recommended version.
-
- Returns
- -------
- JupyterImage
- The corresponding image.
-
- Raises
- ------
- LabControllerError
- An error occurred talking to JupyterLab Controller.
- """
- images = await self._get_images()
- image = images.recommended
- if image is None:
- raise LabControllerError("No recommended image found.")
- return image
-
- async def get_by_reference(self, reference: str) -> JupyterImage:
- """Image with a specific reference.
-
- Returns
- -------
- JupyterImage
- The corresponding image.
-
- Raises
- ------
- LabControllerError
- An error occurred talking to JupyterLab Controller.
- """
- images = await self._get_images()
- image = images.get_by_reference(reference)
- if image is None:
- raise LabControllerError(
- f"No image with reference {reference} found."
- )
- return image
-
- async def _get_images(self) -> LabControllerImages:
- headers = {"Authorization": f"bearer {self._token}"}
- url = urljoin(
- str(config.environment_url),
- f"{self._url_prefix}/spawner/v1/images",
- )
-
- r = await self._http_client.get(url, headers=headers)
- if r.status_code != 200:
- msg = f"Cannot get image status: {r.status_code} {r.reason_phrase}"
- raise LabControllerError(msg)
- try:
- data = r.json()
- return LabControllerImages.model_validate(data)
- except Exception as e:
- msg = f"Invalid response from JupyterLab Controller: {str(e)}"
- raise LabControllerError(msg)
diff --git a/src/noteburst/main.py b/src/noteburst/main.py
index e211c02..a92ec82 100644
--- a/src/noteburst/main.py
+++ b/src/noteburst/main.py
@@ -8,17 +8,20 @@
"""
import json
+from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from importlib.metadata import version
from pathlib import Path
-from typing import AsyncIterator
+import structlog
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
from safir.dependencies.arq import arq_dependency
from safir.dependencies.http_client import http_client_dependency
+from safir.fastapi import ClientRequestError, client_request_error_handler
from safir.logging import configure_logging, configure_uvicorn_logging
from safir.middleware.x_forwarded import XForwardedMiddleware
+from safir.slack.webhook import SlackRouteErrorHandler
from .config import config
from .handlers.external import external_router
@@ -35,6 +38,8 @@
)
configure_uvicorn_logging(config.log_level)
+logger = structlog.get_logger(__name__)
+
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
@@ -70,6 +75,13 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
# Add middleware
app.add_middleware(XForwardedMiddleware)
+if config.slack_webhook_url:
+ SlackRouteErrorHandler.initialize(
+ str(config.slack_webhook_url), "Noteburst", logger
+ )
+
+app.exception_handler(ClientRequestError)(client_request_error_handler)
+
def create_openapi() -> str:
"""Create the OpenAPI spec for static documentation."""
diff --git a/src/noteburst/user/__init__.py b/src/noteburst/user/__init__.py
new file mode 100644
index 0000000..8a8b2d7
--- /dev/null
+++ b/src/noteburst/user/__init__.py
@@ -0,0 +1,3 @@
+from ._user import AuthenticatedUser, User
+
+__all__ = ["AuthenticatedUser", "User"]
diff --git a/src/noteburst/jupyterclient/user.py b/src/noteburst/user/_user.py
similarity index 85%
rename from src/noteburst/jupyterclient/user.py
rename to src/noteburst/user/_user.py
index eaa14f7..23737ed 100644
--- a/src/noteburst/jupyterclient/user.py
+++ b/src/noteburst/user/_user.py
@@ -4,7 +4,6 @@
import time
from dataclasses import dataclass
-from typing import Optional
from urllib.parse import urljoin
import httpx
@@ -25,12 +24,18 @@ class User:
username: str
"""The user's username."""
- uid: Optional[str]
+ uid: int | None
"""The user's UID.
This can be set as `None` if the authentication services provides the UID.
"""
+ gid: int | None
+ """The user's GID.
+
+ This can be set as `None` if the authentication services provides the GID.
+ """
+
async def login(
self,
*,
@@ -41,6 +46,7 @@ async def login(
return await AuthenticatedUser.create(
username=self.username,
uid=self.uid,
+ gid=self.gid,
scopes=scopes,
http_client=http_client,
lifetime=token_lifetime,
@@ -62,7 +68,8 @@ async def create(
cls,
*,
username: str,
- uid: Optional[str],
+ uid: int | None,
+ gid: int | None,
scopes: list[str],
http_client: httpx.AsyncClient,
lifetime: int,
@@ -76,6 +83,9 @@ async def create(
uid
The user's UID. This can be `None` if the authentication service
assigns the UID.
+ gid
+ The user's GID. This can be `None` if the authentication service
+ assigns the GID.
scopes
The scopes the user's token should possess.
http_client
@@ -87,13 +97,14 @@ async def create(
token_request_data = {
"username": username,
"name": "Noteburst",
- "token_type": "user",
- "token_name": f"noteburst {str(float(time.time()))}",
+ "token_type": "service",
"scopes": scopes,
"expires": int(time.time() + lifetime),
}
if uid:
token_request_data["uid"] = uid
+ if gid:
+ token_request_data["gid"] = gid
r = await http_client.post(
token_url,
headers={
@@ -108,6 +119,7 @@ async def create(
return cls(
username=username,
uid=uid,
+ gid=gid,
token=body["token"],
scopes=scopes,
)
diff --git a/src/noteburst/worker/functions/keepalive.py b/src/noteburst/worker/functions/keepalive.py
index 1d12402..e50f448 100644
--- a/src/noteburst/worker/functions/keepalive.py
+++ b/src/noteburst/worker/functions/keepalive.py
@@ -5,7 +5,7 @@
import sys
from typing import Any
-from noteburst.jupyterclient.jupyterlab import JupyterError
+from rubin.nublado.client.exceptions import JupyterWebSocketError
async def keep_alive(ctx: dict[Any, Any]) -> str:
@@ -30,10 +30,10 @@ async def keep_alive(ctx: dict[Any, Any]) -> str:
kernel_name="LSST"
) as session:
await session.run_python("print('alive')")
- except JupyterError as e:
- logger.error("keep_alive error", jupyter_status=e.status)
- if e.status >= 400 and e.status < 500:
- logger.error(
+ except JupyterWebSocketError as e:
+ logger.exception("keep_alive error", jupyter_status=e.status)
+ if e.status and e.status >= 400 and e.status < 500:
+ logger.exception(
"Authentication error to Jupyter. Forcing worker shutdown",
jupyter_status=e.status,
)
diff --git a/src/noteburst/worker/functions/nbexec.py b/src/noteburst/worker/functions/nbexec.py
index a947097..22e372c 100644
--- a/src/noteburst/worker/functions/nbexec.py
+++ b/src/noteburst/worker/functions/nbexec.py
@@ -4,14 +4,17 @@
from __future__ import annotations
+import asyncio
import json
import sys
-from typing import Any, cast
+from datetime import timedelta
+from typing import Any
from arq import Retry
+from rubin.nublado.client.exceptions import NubladoClientSlackException
+from safir.slack.blockkit import SlackTextField
-from noteburst.exceptions import NbexecTaskError
-from noteburst.jupyterclient.jupyterlab import JupyterClient, JupyterError
+from noteburst.exceptions import NbexecTaskError, NbexecTaskTimeoutError
async def nbexec(
@@ -20,6 +23,7 @@ async def nbexec(
ipynb: str,
kernel_name: str = "LSST",
enable_retry: bool = True,
+ timeout: timedelta | None = None, # noqa: ASYNC109
) -> str:
"""Execute a notebook, as an asynchronous arq worker task.
@@ -40,37 +44,81 @@ async def nbexec(
The notebook execution result, a JSON-serialized
`NotebookExecutionResult` object.
"""
+ job_id = ctx.get("job_id", "unknown")
logger = ctx["logger"].bind(
task="nbexec",
job_attempt=ctx.get("job_try", -1),
- job_id=ctx.get("job_id", "unknown"),
+ job_id=job_id,
kernel_name=kernel_name,
)
logger.debug("Running nbexec")
- jupyter_client = cast(JupyterClient, ctx["jupyter_client"])
+ jupyter_client = ctx["jupyter_client"]
- parsed_notebook = json.loads(ipynb)
- logger.debug("Got ipynb", ipynb=parsed_notebook)
- try:
- execution_result = await jupyter_client.execute_notebook(
- parsed_notebook, kernel_name=kernel_name
- )
- logger.info("nbexec finished", error=execution_result.error)
- except JupyterError as e:
- logger.error("nbexec error", jupyter_status=e.status)
- if e.status >= 400 and e.status < 500:
- logger.error(
- "Authentication error to Jupyter. Forcing worker shutdown",
- jupyter_status=e.status,
+ async with jupyter_client.open_lab_session(
+ notebook_name=job_id, kernel_name=kernel_name
+ ) as sess:
+ parsed_notebook = json.loads(ipynb)
+ logger.debug("Got ipynb", ipynb=parsed_notebook)
+ try:
+ execution_result = await asyncio.wait_for(
+ sess.run_notebook_via_rsp_extension(path=None, content=ipynb),
+ timeout=timeout.total_seconds() if timeout else None,
)
- sys.exit("400 class error from Jupyter")
- else:
- # trigger re-try with increasing back-off
- if enable_retry:
+ logger.info("nbexec finished", error=execution_result.error)
+ except TimeoutError as e:
+ raise NbexecTaskTimeoutError.from_exception(e) from e
+ except NubladoClientSlackException as e:
+ if hasattr(e, "status"):
+ logger.exception("nbexec error", jupyter_status=e.status)
+ else:
+ logger.exception("nbexec error")
+ if "slack" in ctx and "slack_message_factory" in ctx:
+ slack_client = ctx["slack"]
+ message = e.to_slack()
+ message.fields.append(
+ SlackTextField(
+ heading="Job ID", text=ctx.get("job_id", "unknown")
+ )
+ )
+ message.fields.append(
+ SlackTextField(
+ heading="Attempt",
+ text=str(ctx.get("job_try", "unknown")),
+ )
+ )
+ await slack_client.post(message)
+
+ if hasattr(e, "status") and e.status >= 400 and e.status < 500:
+ logger.exception(
+ "Authentication error to Jupyter. Forcing worker shutdown",
+ jupyter_status=e.status,
+ )
+
+ if "slack" in ctx and "slack_message_factory" in ctx:
+ slack_client = ctx["slack"]
+ message = ctx["slack_message_factory"](
+ "Noteburst worker shutting down due to Jupyter "
+ "authentication error during nbexec."
+ )
+ message.fields.append(
+ SlackTextField(
+ heading="Job ID", text=ctx.get("job_id", "unknown")
+ )
+ )
+ message.fields.append(
+ SlackTextField(
+ heading="Attempt",
+ text=str(ctx.get("job_try", "unknown")),
+ )
+ )
+ await slack_client.post(message)
+
+ sys.exit("400 class error from Jupyter")
+ elif enable_retry:
logger.warning("nbexec triggering retry")
- raise Retry(defer=ctx["job_try"] * 5)
+ raise Retry(defer=ctx["job_try"] * 5) from None
else:
- raise NbexecTaskError.from_exception(e)
+ raise NbexecTaskError.from_exception(e) from e
- return execution_result.model_dump_json()
+ return execution_result.model_dump_json()
diff --git a/src/noteburst/worker/functions/ping.py b/src/noteburst/worker/functions/ping.py
index dab176e..b4e8868 100644
--- a/src/noteburst/worker/functions/ping.py
+++ b/src/noteburst/worker/functions/ping.py
@@ -6,6 +6,7 @@
async def ping(ctx: dict[Any, Any]) -> str:
+ """Log a ping message and return a string."""
logger = ctx["logger"].bind(task="ping")
logger.info("Running ping")
diff --git a/src/noteburst/worker/functions/runpython.py b/src/noteburst/worker/functions/runpython.py
index ee05707..6bb6b51 100644
--- a/src/noteburst/worker/functions/runpython.py
+++ b/src/noteburst/worker/functions/runpython.py
@@ -1,3 +1,5 @@
+"""An Arq worker function to execute Python code in a JupyterLab pod."""
+
from __future__ import annotations
from typing import Any
diff --git a/src/noteburst/worker/identity.py b/src/noteburst/worker/identity.py
index 77d2731..4341fd8 100644
--- a/src/noteburst/worker/identity.py
+++ b/src/noteburst/worker/identity.py
@@ -8,12 +8,12 @@
from dataclasses import dataclass
from pathlib import Path
-from typing import Optional
+from typing import Annotated
import structlog
import yaml
from aioredlock import Aioredlock, Lock, LockError
-from pydantic import BaseModel, RootModel
+from pydantic import BaseModel, Field, RootModel
from noteburst.config import WorkerConfig
@@ -23,17 +23,34 @@ class IdentityModel(BaseModel):
configuration file.
"""
- username: str
- """The username of the user account."""
+ username: Annotated[
+ str, Field(description="The username of the user account.")
+ ]
- uid: Optional[str] = None
- """The UID of the user account.
-
- This can be `None` if the authentication system assigns the UID.
- """
+ uid: Annotated[
+ int | None,
+ Field(
+ description=(
+ "The UID of the user account. This can be `None` if the "
+ "authentication system assigns the UID."
+ )
+ ),
+ ] = None
+
+ gid: Annotated[
+ int | None,
+ Field(
+ description=(
+ "The GID of the user account. This can be `None` if the "
+ "authentication system assigns the GID."
+ )
+ ),
+ ] = None
class IdentityConfigModel(RootModel):
+ """Model for the IdentityConfigModel-based configuration file."""
+
root: list[IdentityModel]
@classmethod
@@ -49,9 +66,12 @@ class IdentityClaim:
username: str
"""The username of the user account."""
- uid: Optional[str]
+ uid: int | None
"""The UID of the user account."""
+ gid: int | None
+ """The GID of the user account."""
+
lock: Lock
"""The aioredlock lock that this claim holds."""
@@ -92,7 +112,7 @@ def __init__(
) -> None:
self.lock_manager = lock_manager
self.identities = identities
- self._current_identity: Optional[IdentityClaim] = None
+ self._current_identity: IdentityClaim | None = None
self._logger = structlog.get_logger(__name__)
@classmethod
@@ -111,12 +131,9 @@ def from_config(cls, config: WorkerConfig) -> IdentityManager:
"""
lock_manager = Aioredlock(config.aioredlock_redis_config)
- identities = [
- identity
- for identity in IdentityConfigModel.from_yaml(
- config.identities_path
- ).root
- ]
+ identities = list(
+ IdentityConfigModel.from_yaml(config.identities_path).root
+ )
return cls(lock_manager=lock_manager, identities=identities)
@@ -133,7 +150,7 @@ async def _release_identity(self) -> None:
self._logger.info("Released worker user identity")
async def get_identity(
- self, _identities: Optional[list[IdentityModel]] = None
+ self, _identities: list[IdentityModel] | None = None
) -> IdentityClaim:
"""Get a unique identity (either claiming a new identity or providing
the already-claimed identity).
@@ -145,10 +162,7 @@ async def get_identity(
IdentityClaim
Information about the Science Platform identity.
"""
- if _identities:
- identities = _identities
- else:
- identities = self.identities
+ identities = _identities if _identities else self.identities
if self._current_identity:
if self._current_identity.valid:
@@ -169,7 +183,10 @@ async def get_identity(
self._logger.info("Claimed identity", username=identity.username)
self._current_identity = IdentityClaim(
- username=identity.username, uid=identity.uid, lock=lock
+ username=identity.username,
+ uid=identity.uid,
+ gid=identity.gid,
+ lock=lock,
)
return self._current_identity
@@ -192,13 +209,20 @@ async def get_next_identity(
await self._release_identity()
for i, identity in enumerate(self.identities):
- if identity.username == prev_identity.username:
- break
+ # Find the same identity as before to then get the next one
+ if identity.username != prev_identity.username:
+ continue
+
+ if i + 1 >= len(self.identities):
+ raise IdentityClaimError(
+ "Could not claim an Science Platform identity (none "
+ "available)."
+ )
- if i + 1 >= len(self.identities):
- raise IdentityClaimError(
- "Could not claim an Science Platform identity (none "
- "available)."
+ return await self.get_identity(
+ _identities=self.identities[i + 1 :]
)
- return await self.get_identity(_identities=self.identities[i + 1 :])
+ raise IdentityClaimError(
+ "Could not claim an Science Platform identity (none available)."
+ )
diff --git a/src/noteburst/worker/main.py b/src/noteburst/worker/main.py
index d1b130f..2172c11 100644
--- a/src/noteburst/worker/main.py
+++ b/src/noteburst/worker/main.py
@@ -2,30 +2,52 @@
from __future__ import annotations
-from typing import Any
+from datetime import UTC, datetime
+from typing import Any, ClassVar
import httpx
+import humanize
+import rubin.nublado.client.models as nc_models
import structlog
from arq import cron
+from rubin.nublado.client import NubladoClient
+from rubin.nublado.client.exceptions import JupyterProtocolError
from safir.logging import configure_logging
+from safir.slack.blockkit import SlackMessage, SlackTextField
+from safir.slack.webhook import SlackWebhookClient
+from structlog.stdlib import BoundLogger
from noteburst.config import WorkerConfig, WorkerKeepAliveSetting
-from noteburst.jupyterclient.jupyterlab import (
- JupyterClient,
- JupyterConfig,
- JupyterError,
-)
-from noteburst.jupyterclient.user import User
+from noteburst.user import User
from .functions import keep_alive, nbexec, ping, run_python
-from .identity import IdentityManager
+from .identity import IdentityClaim, IdentityManager
config = WorkerConfig()
+async def _get_client_user(
+ identity: IdentityClaim,
+ config: WorkerConfig,
+ http_client: httpx.AsyncClient,
+ logger: BoundLogger,
+) -> nc_models.User:
+ user = User(username=identity.username, uid=identity.uid, gid=identity.gid)
+
+ authed_user = await user.login(
+ scopes=config.parsed_worker_token_scopes,
+ http_client=http_client,
+ token_lifetime=config.worker_token_lifetime,
+ )
+ logger.info("Authenticated the worker's user.")
+
+ return nc_models.User(
+ username=authed_user.username, token=authed_user.token
+ )
+
+
async def startup(ctx: dict[Any, Any]) -> None:
- """Runs during working start-up to set up the JupyterLab client and
- populate the worker context.
+ """Set up worker context on startup.
Notes
-----
@@ -48,37 +70,53 @@ async def startup(ctx: dict[Any, Any]) -> None:
http_client = httpx.AsyncClient()
ctx["http_client"] = http_client
- jupyter_config = JupyterConfig(
- url_prefix=config.jupyterhub_path_prefix,
- image_selector=config.image_selector,
- image_reference=config.image_reference,
- )
+ if config.slack_webhook_url:
+ slack_client = SlackWebhookClient(
+ str(config.slack_webhook_url),
+ "Noteburst worker",
+ logger=logger,
+ )
+ ctx["slack"] = slack_client
+
+ jupyter_image: nc_models.NubladoImage | None = None
+ if config.image_selector == "reference":
+ jupyter_image = nc_models.NubladoImageByReference(
+ reference=config.image_reference
+ )
+ elif config.image_selector == "weekly":
+ jupyter_image = nc_models.NubladoImageByClass(
+ image_class=nc_models.NubladoImageClass.LATEST_WEEKLY
+ )
+ else:
+ # "Recommended" is default
+ jupyter_image = nc_models.NubladoImageByClass()
identity = await identity_manager.get_identity()
while True:
logger = logger.bind(worker_username=identity.username)
- user = User(username=identity.username, uid=identity.uid)
- authed_user = await user.login(
- scopes=config.parsed_worker_token_scopes,
- http_client=http_client,
- token_lifetime=config.worker_token_lifetime,
+ jupyter_client = NubladoClient(
+ user=await _get_client_user(identity, config, http_client, logger),
+ base_url=str(config.environment_url),
+ logger=logger,
+ hub_route=config.jupyterhub_path_prefix,
)
- logger.info("Authenticated the worker's user.")
- jupyter_client = JupyterClient(
- user=authed_user, logger=logger, config=jupyter_config
- )
- await jupyter_client.log_into_hub()
+ await jupyter_client.auth_to_hub()
try:
- image_info = await jupyter_client.spawn_lab()
- logger = logger.bind(image_ref=image_info.reference)
- async for progress in jupyter_client.spawn_progress():
+ await jupyter_client.spawn_lab(config=jupyter_image)
+ if config.image_reference:
+ logger = logger.bind(image_ref=config.image_reference)
+ else:
+ logger = logger.bind(image_ref=config.image_selector)
+ # We don't currently expose the reference of the actually-spawned
+ # image in the client, so put that down as a to-do item.
+ async for _ in jupyter_client.watch_spawn_progress():
continue
- await jupyter_client.log_into_lab()
+ await jupyter_client.auth_to_lab()
break
- except JupyterError as e:
+ except JupyterProtocolError as e:
logger.warning("Error spawning pod, will re-try with new identity")
logger.debug("Details for error spawning pod", detail=str(e))
identity = await identity_manager.get_next_identity(identity)
@@ -86,14 +124,51 @@ async def startup(ctx: dict[Any, Any]) -> None:
ctx["jupyter_client"] = jupyter_client
ctx["logger"] = logger
- logger.info("Start up complete")
+ logger.info(
+ "Noteburst worker startup complete.",
+ image_selector=config.image_selector,
+ image_reference=config.image_reference,
+ )
+
+ if "slack" in ctx:
+ slack_client = ctx["slack"]
+
+ date_created = datetime.now(tz=UTC)
+
+ def create_message(message: str) -> SlackMessage:
+ now = datetime.now(tz=UTC)
+ age = now - date_created
+
+ return SlackMessage(
+ message=message,
+ fields=[
+ SlackTextField(
+ heading="Username",
+ text=identity.username,
+ ),
+ SlackTextField(
+ heading="Image Selector",
+ text=config.image_selector,
+ ),
+ # Losing Image field here--again, see, "get real running
+ # image" from client.
+ SlackTextField(
+ heading="Age", text=humanize.naturaldelta(age)
+ ),
+ ],
+ )
+
+ ctx["slack_message_factory"] = create_message
+
+ # Make a start-up message
+ await slack_client.post(
+ ctx["slack_message_factory"]("Noteburst worker started")
+ )
async def shutdown(ctx: dict[Any, Any]) -> None:
- """Runs during worker shut-down to release the JupyterLab resources
- and identity claim.
- """
- if "logger" in ctx.keys():
+ """Clean up the worker context on shutdown."""
+ if "logger" in ctx:
logger = ctx["logger"]
else:
logger = structlog.get_logger(__name__)
@@ -141,17 +216,25 @@ async def shutdown(ctx: dict[Any, Any]) -> None:
logger.info("Worker shutdown complete.")
+ if "slack" in ctx and "slack_message_factory" in ctx:
+ slack_client = ctx["slack"]
+ await slack_client.post(
+ ctx["slack_message_factory"](
+ "Noteburst worker shut down complete."
+ )
+ )
+
# For info on ignoring the type checking here, see
# https://github.com/samuelcolvin/arq/issues/249
-cron_jobs: list[cron] = [] # type: ignore
+cron_jobs: list[cron] = [] # type: ignore [valid-type]
if config.worker_keepalive == WorkerKeepAliveSetting.fast:
f = cron(keep_alive, second={0, 30}, unique=False)
cron_jobs.append(f)
elif config.worker_keepalive == WorkerKeepAliveSetting.normal:
f = cron(
keep_alive,
- minute={0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55},
+ minute={0, 15, 30, 45},
unique=False,
)
cron_jobs.append(f)
@@ -163,7 +246,7 @@ class WorkerSettings:
See `arq.worker.Worker` for details on these attributes.
"""
- functions = [ping, nbexec, run_python]
+ functions: ClassVar = [ping, nbexec, run_python]
cron_jobs = cron_jobs
@@ -176,3 +259,5 @@ class WorkerSettings:
on_shutdown = shutdown
job_timeout = config.job_timeout
+
+ max_jobs = config.max_concurrent_jobs
diff --git a/tests/conftest.py b/tests/conftest.py
index 7e4dfa0..bf512b3 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -3,28 +3,31 @@
from __future__ import annotations
import contextlib
-from typing import Any, AsyncGenerator, AsyncIterator
+from collections.abc import AsyncGenerator, AsyncIterator
+from pathlib import Path
+from typing import Any
+from unittest.mock import patch
import pytest
import pytest_asyncio
import respx
import structlog
-import websockets
-from _pytest.monkeypatch import MonkeyPatch
from asgi_lifespan import LifespanManager
from fastapi import FastAPI
-from httpx import AsyncClient
-
-from noteburst import main
-from tests.support.arq import MockIdentityClaim, MockIdentityManager
-from tests.support.jupyter import (
+from httpx import ASGITransport, AsyncClient
+from rubin.nublado.client.testing import (
MockJupyter,
MockJupyterWebSocket,
mock_jupyter,
mock_jupyter_websocket,
)
+
+from noteburst import main
+from tests.support.arq import MockIdentityClaim, MockIdentityManager
from tests.support.labcontroller import MockLabController, mock_labcontroller
+BASE_URL = "https://example.com"
+
@pytest_asyncio.fixture
async def app() -> AsyncIterator[FastAPI]:
@@ -42,7 +45,9 @@ async def client(app: FastAPI) -> AsyncIterator[AsyncClient]:
"""Return an ``httpx.AsyncClient`` configured to talk to the test app."""
headers = {"X-Auth-Request-User": "user"}
async with AsyncClient(
- app=app, base_url="https://example.com/", headers=headers
+ transport=ASGITransport(app=app),
+ base_url=BASE_URL,
+ headers=headers,
) as client:
yield client
@@ -54,24 +59,31 @@ def labcontroller(respx_mock: respx.Router) -> MockLabController:
@pytest.fixture
-def jupyter(monkeypatch: MonkeyPatch, respx_mock: respx.Router) -> MockJupyter:
+async def jupyter(
+ respx_mock: respx.Router, tmp_path: Path
+) -> AsyncIterator[MockJupyter]:
"""Mock out JupyterHub/Lab API."""
- jupyter_mock = mock_jupyter(respx_mock)
+ jupyter_mock = mock_jupyter(
+ respx_mock, base_url=BASE_URL, user_dir=tmp_path
+ )
@contextlib.asynccontextmanager
- async def mock_websocket_connect(
- url: str, **kwargs: Any
- ) -> AsyncGenerator[MockJupyterWebSocket, None]:
- yield mock_jupyter_websocket(url, jupyter_mock)
-
- monkeypatch.setattr(websockets, "connect", mock_websocket_connect)
+ async def mock_connect(
+ url: str,
+ extra_headers: dict[str, str],
+ max_size: int | None,
+ open_timeout: int,
+ ) -> AsyncGenerator[MockJupyterWebSocket]:
+ yield mock_jupyter_websocket(url, extra_headers, jupyter_mock)
- return jupyter_mock
+ with patch("rubin.nublado.client.nubladoclient.websocket_connect") as mock:
+ mock.side_effect = mock_connect
+ yield jupyter_mock
@pytest.fixture
def worker_context() -> dict[Any, Any]:
- """A mock ctx (context) fixture for arq workers."""
+ """Mock the ctx (context) for arq workers."""
ctx: dict[Any, Any] = {}
# Prep identity_manager
diff --git a/tests/handlers/external_test.py b/tests/handlers/external_test.py
index 2d9062f..26e475d 100644
--- a/tests/handlers/external_test.py
+++ b/tests/handlers/external_test.py
@@ -10,7 +10,7 @@
@pytest.mark.asyncio
async def test_get_index(client: AsyncClient) -> None:
- """Test ``GET /noteburst/``"""
+ """Test ``GET /noteburst/``."""
response = await client.get("/noteburst/")
assert response.status_code == 200
data = response.json()
diff --git a/tests/handlers/internal_test.py b/tests/handlers/internal_test.py
index 7ef89c9..1eabfb2 100644
--- a/tests/handlers/internal_test.py
+++ b/tests/handlers/internal_test.py
@@ -10,7 +10,7 @@
@pytest.mark.asyncio
async def test_get_index(client: AsyncClient) -> None:
- """Test ``GET /``"""
+ """Test ``GET /``."""
response = await client.get("/")
assert response.status_code == 200
data = response.json()
diff --git a/tests/handlers/v1_test.py b/tests/handlers/v1_test.py
index 4b51b1f..ef3dbdb 100644
--- a/tests/handlers/v1_test.py
+++ b/tests/handlers/v1_test.py
@@ -50,8 +50,8 @@ async def test_post_nbexec(
data2 = response.json()
assert data == data2
- assert "source" not in data2.keys()
- assert "ipynb" not in data2.keys()
+ assert "source" not in data2
+ assert "ipynb" not in data2
# Request the job with the source ipynb included
response = await client.get(job_url, params={"source": "true"})
@@ -81,3 +81,12 @@ async def test_post_nbexec(
assert data["status"] == "complete"
assert data["success"] is True
assert data["ipynb"] == sample_ipynb_executed
+
+ # Request a job that doesn't exist
+ response = await client.get("/noteburst/v1/notebooks/unknown")
+ assert response.status_code == 404
+ data = response.json()
+ print(data)
+ assert data["detail"][0]["type"] == "unknown_job"
+ assert data["detail"][0]["loc"] == ["path", "job_id"]
+ assert data["detail"][0]["msg"] == "Job not found"
diff --git a/tests/jupyterclient/jupyterclient_test.py b/tests/jupyterclient/jupyterclient_test.py
deleted file mode 100644
index 7469f55..0000000
--- a/tests/jupyterclient/jupyterclient_test.py
+++ /dev/null
@@ -1,57 +0,0 @@
-"""Test the JupyterClient."""
-
-from __future__ import annotations
-
-import httpx
-import pytest
-import respx
-import structlog
-
-from noteburst.config import JupyterImageSelector
-from noteburst.jupyterclient.jupyterlab import JupyterClient, JupyterConfig
-from noteburst.jupyterclient.user import User
-from tests.support.gafaelfawr import mock_gafaelfawr
-from tests.support.jupyter import MockJupyter
-from tests.support.labcontroller import MockLabController
-
-
-@pytest.mark.asyncio
-async def test_jupyterclient(
- respx_mock: respx.Router,
- jupyter: MockJupyter,
- labcontroller: MockLabController,
-) -> None:
- user = User(username="someuser", uid="1234")
- mock_gafaelfawr(
- respx_mock=respx_mock, username=user.username, uid=user.uid
- )
-
- logger = structlog.get_logger(__name__)
-
- jupyter_config = JupyterConfig(
- image_selector=JupyterImageSelector.recommended
- )
-
- async with httpx.AsyncClient() as http_client:
- authed_user = await user.login(
- scopes=["exec:notebook"],
- http_client=http_client,
- token_lifetime=3600,
- )
- async with JupyterClient(
- user=authed_user, logger=logger, config=jupyter_config
- ) as jupyter_client:
- await jupyter_client.log_into_hub()
-
- image_info = await jupyter_client.spawn_lab()
- print(image_info)
- async for progress in jupyter_client.spawn_progress():
- print(progress)
-
- await jupyter_client.log_into_lab()
-
- # FIXME the test code for this isn't full set up yet
- # async with jupyter_client.open_lab_session() as lab_session:
- # print(lab_session.kernel_id)
-
- await jupyter_client.stop_lab()
diff --git a/tests/jupyterclient/user_test.py b/tests/jupyterclient/user_test.py
index c67d5aa..5fc9e94 100644
--- a/tests/jupyterclient/user_test.py
+++ b/tests/jupyterclient/user_test.py
@@ -1,4 +1,4 @@
-"""Tests for the noteburst.jupyterclient.user module."""
+"""Tests for the noteburst.user module."""
from __future__ import annotations
@@ -6,14 +6,14 @@
import pytest
import respx
-from noteburst.jupyterclient.user import User
+from noteburst.user import User
from tests.support.gafaelfawr import mock_gafaelfawr
@pytest.mark.asyncio
async def test_generate_token(respx_mock: respx.Router) -> None:
- u = User(username="someuser", uid="1234")
- mock_gafaelfawr(respx_mock, u.username, u.uid)
+ u = User(username="someuser", uid=1234, gid=5678)
+ mock_gafaelfawr(respx_mock, u.username, u.uid, u.gid)
scopes = ["exec:notebook"]
async with httpx.AsyncClient() as http_client:
@@ -21,6 +21,7 @@ async def test_generate_token(respx_mock: respx.Router) -> None:
scopes=scopes, http_client=http_client, token_lifetime=3600
)
assert user.username == "someuser"
- assert user.uid == "1234"
+ assert user.uid == 1234
+ assert user.gid == 5678
assert user.scopes == ["exec:notebook"]
assert user.token.startswith("gt-")
diff --git a/tests/support/arq.py b/tests/support/arq.py
index 11aca1f..4d61635 100644
--- a/tests/support/arq.py
+++ b/tests/support/arq.py
@@ -3,7 +3,6 @@
from __future__ import annotations
from dataclasses import dataclass
-from typing import Optional
from noteburst.worker.identity import IdentityClaimError
@@ -35,7 +34,7 @@ class MockIdentityManager:
"""
def __init__(self) -> None:
- self._current_identity: Optional[MockIdentityClaim] = None
+ self._current_identity: MockIdentityClaim | None = None
async def get_identity(self) -> MockIdentityClaim:
if self._current_identity:
diff --git a/tests/support/gafaelfawr.py b/tests/support/gafaelfawr.py
index 8a5fc80..2d854bd 100644
--- a/tests/support/gafaelfawr.py
+++ b/tests/support/gafaelfawr.py
@@ -6,7 +6,6 @@
import json
import os
import time
-from typing import Optional
from unittest.mock import ANY
from urllib.parse import urljoin
@@ -18,7 +17,7 @@
__all__ = ["make_gafaelfawr_token", "mock_gafaelfawr"]
-def make_gafaelfawr_token(username: Optional[str] = None) -> str:
+def make_gafaelfawr_token(username: str | None = None) -> str:
"""Create a random or user Gafaelfawr token.
If a username is given, embed the username in the key portion of the token
@@ -36,8 +35,9 @@ def make_gafaelfawr_token(username: Optional[str] = None) -> str:
def mock_gafaelfawr(
respx_mock: respx.Router,
- username: Optional[str] = None,
- uid: Optional[str] = None,
+ username: str | None = None,
+ uid: int | None = None,
+ gid: int | None = None,
) -> None:
"""Mock out the call to Gafaelfawr ``/auth/api/v1/tokens`` endpoint to
create a user token.
@@ -51,26 +51,23 @@ def mock_gafaelfawr(
def handler(request: httpx.Request) -> httpx.Response:
request_json = json.loads(request.content.decode("utf-8"))
- # Skipping this assert that originally came from
- # mobu/aiohttp/aioresponses because httpx.Request seems to obfuscate
- # the authorization header after it's created; we'd need to figure
- # out how to work around that.
- # request_headers = request.headers
- # assert request_headers["authorization"] == f"Bearer {admin_token}"
+ # Note httpx.Request seems to obfuscate the authorization header
+ # so we can't check it here.
assert request_json == {
"username": ANY,
- "token_type": "user",
- "token_name": ANY,
+ "token_type": "service",
"scopes": ["exec:notebook"],
"expires": ANY,
"name": "Noteburst",
"uid": ANY,
+ "gid": ANY,
}
if username:
assert request_json["username"] == username
if uid:
assert request_json["uid"] == uid
- assert request_json["token_name"].startswith("noteburst ")
+ if gid:
+ assert request_json["gid"] == gid
assert request_json["expires"] > time.time()
response = {"token": make_gafaelfawr_token(request_json["username"])}
return httpx.Response(200, json=response, request=request)
diff --git a/tests/support/jupyter.py b/tests/support/jupyter.py
deleted file mode 100644
index 63b8443..0000000
--- a/tests/support/jupyter.py
+++ /dev/null
@@ -1,431 +0,0 @@
-"""Mock JupyterHub (and JupyterLab) for testing."""
-
-from __future__ import annotations
-
-import asyncio
-import json
-import re
-from base64 import urlsafe_b64decode
-from contextlib import redirect_stdout
-from datetime import datetime, timedelta, timezone
-from enum import Enum
-from io import StringIO
-from traceback import format_exc
-from typing import Any, AsyncIterator, Optional
-from unittest.mock import ANY, AsyncMock, Mock
-from uuid import uuid4
-
-import httpx
-import respx
-import structlog
-from websockets.client import WebSocketClientProtocol
-
-from noteburst.config import config
-from noteburst.jupyterclient.jupyterlab import JupyterLabSession
-
-_GET_NODE = """
-from rubin_jupyter_utils.lab.notebook.utils import get_node
-print(get_node(), end="")
-"""
-"""Python code to get the node on which the lab is running."""
-
-
-class JupyterAction(Enum):
- LOGIN = "login"
- HOME = "home"
- HUB = "hub"
- USER = "user"
- PROGRESS = "progress"
- SPAWN = "spawn"
- SPAWN_PENDING = "spawn_pending"
- LAB = "lab"
- DELETE_LAB = "delete_lab"
- CREATE_SESSION = "create_session"
- DELETE_SESSION = "delete_session"
-
-
-class JupyterState(Enum):
- LOGGED_OUT = "logged out"
- LOGGED_IN = "logged in"
- SPAWN_PENDING = "spawn pending"
- LAB_RUNNING = "lab running"
-
-
-def url_for_path(route: str) -> str:
- """Construct a URL for JupyterHub/Proxy."""
- env_url = str(config.environment_url)
- if env_url.endswith("/"):
- env_url = env_url[:-1]
- return f"{env_url}/nb/{route}"
-
-
-def url_for_pattern(route: str) -> str:
- """Construct a URL for JupyterHub/Proxy."""
- env_url = str(config.environment_url)
- if env_url.endswith("/"):
- env_url = env_url[:-1]
- prefix = re.escape(f"{env_url}/nb/")
- return prefix + route
-
-
-class MockJupyter:
- """A mock Jupyter state machine.
-
- This should be invoked via mocked HTTP calls so that tests can simulate
- making REST calls to the real JupyterHub/Lab.
- """
-
- def __init__(self) -> None:
- self.sessions: dict[str, JupyterLabSession] = {}
- self.state: dict[str, JupyterState] = {}
- self.delete_immediate = True
- self.spawn_timeout = False
- self._delete_at: dict[str, Optional[datetime]] = {}
- self._fail: dict[str, dict[JupyterAction, bool]] = {}
-
- def fail(self, user: str, action: JupyterAction) -> None:
- """Configure the given action to fail for the given user."""
- if user not in self._fail:
- self._fail[user] = {}
- self._fail[user][action] = True
-
- def login(self, request: httpx.Request) -> httpx.Response:
- """Mock the JupyterHub log in response."""
- user = self._get_user(request.headers["Authorization"])
- if JupyterAction.LOGIN in self._fail.get(user, {}):
- return httpx.Response(500, request=request)
- state = self.state.get(user, JupyterState.LOGGED_OUT)
- if state == JupyterState.LOGGED_OUT:
- self.state[user] = JupyterState.LOGGED_IN
- return httpx.Response(200, request=request)
-
- def user(self, request: httpx.Request) -> httpx.Response:
- user = self._get_user(request.headers["Authorization"])
- if JupyterAction.USER in self._fail.get(user, {}):
- return httpx.Response(500, request=request)
- assert str(request.url).endswith(f"/hub/api/users/{user}")
- state = self.state.get(user, JupyterState.LOGGED_OUT)
- if state == JupyterState.SPAWN_PENDING:
- server = {"name": "", "pending": "spawn", "ready": False}
- body = {"name": user, "servers": {"": server}}
- elif state == JupyterState.LAB_RUNNING:
- delete_at = self._delete_at.get(user)
- if delete_at and (datetime.now(tz=timezone.utc)) > delete_at:
- del self._delete_at[user]
- self.state[user] = JupyterState.LOGGED_IN
- if delete_at:
- server = {"name": "", "pending": "delete", "ready": False}
- else:
- server = {"name": "", "pending": None, "ready": True}
- body = {"name": user, "servers": {"": server}}
- else:
- body = {"name": user, "servers": {}}
- return httpx.Response(200, json=body, request=request)
-
- async def progress(self, request: httpx.Request) -> httpx.Response:
- user = self._get_user(request.headers["Authorization"])
- assert str(request.url).endswith(
- f"/hub/api/users/{user}/server/progress"
- )
- state = self.state.get(user, JupyterState.LOGGED_OUT)
- assert state in (JupyterState.SPAWN_PENDING, JupyterState.LAB_RUNNING)
- if JupyterAction.PROGRESS in self._fail.get(user, {}):
- body = (
- 'data: {"progress": 0, "message": "Server requested"}\n'
- 'data: {"progress": 50, "message": "Spawning server..."}\n'
- 'data: {"progress": 75, "message": "Spawn failed!"}\n'
- )
- elif state == JupyterState.LAB_RUNNING:
- body = (
- 'data: {"progress": 100, "ready": true, "message": "Ready"}\n'
- )
- elif self.spawn_timeout:
- # Cause the spawn to time out by pausing for longer than the test
- # should run for and then returning nothing.
- await asyncio.sleep(60)
- body = ""
- else:
- self.state[user] = JupyterState.LAB_RUNNING
- body = (
- 'data: {"progress": 0, "message": "Server requested"}\n'
- 'data: {"progress": 50, "message": "Spawning server..."}\n'
- 'data: {"progress": 100, "ready": true, "message": "Ready"}\n'
- )
- return httpx.Response(200, text=body, request=request)
-
- def spawn(self, request: httpx.Request) -> httpx.Response:
- user = self._get_user(request.headers["Authorization"])
- if JupyterAction.SPAWN in self._fail.get(user, {}):
- return httpx.Response(500, request=request)
- state = self.state.get(user, JupyterState.LOGGED_OUT)
- assert state == JupyterState.LOGGED_IN
- self.state[user] = JupyterState.SPAWN_PENDING
- return httpx.Response(
- 302,
- headers={"Location": url_for_path(f"hub/spawn-pending/{user}")},
- request=request,
- )
-
- def spawn_pending(self, request: httpx.Request) -> httpx.Response:
- user = self._get_user(request.headers["Authorization"])
- assert str(request.url).endswith(f"/hub/spawn-pending/{user}")
- if JupyterAction.SPAWN_PENDING in self._fail.get(user, {}):
- return httpx.Response(500, request=request)
- state = self.state.get(user, JupyterState.LOGGED_OUT)
- assert state == JupyterState.SPAWN_PENDING
- return httpx.Response(200, request=request)
-
- def missing_lab(self, request: httpx.Request) -> httpx.Response:
- user = self._get_user(request.headers["Authorization"])
- assert str(request.url).endswith(f"/hub/user/{user}/lab")
- return httpx.Response(503, request=request)
-
- def lab(self, request: httpx.Request) -> httpx.Response:
- user = self._get_user(request.headers["Authorization"])
- assert str(request.url).endswith(f"/user/{user}/lab")
- if JupyterAction.LAB in self._fail.get(user, {}):
- return httpx.Response(500, request=request)
- state = self.state.get(user, JupyterState.LOGGED_OUT)
- if state == JupyterState.LAB_RUNNING:
- return httpx.Response(200, request=request)
- else:
- return httpx.Response(
- 302, headers={"Location": url_for_path(f"hub/user/{user}/lab")}
- )
-
- def delete_lab(self, request: httpx.Request) -> httpx.Response:
- user = self._get_user(request.headers["Authorization"])
- assert str(request.url).endswith(f"/users/{user}/server")
- if JupyterAction.DELETE_LAB in self._fail.get(user, {}):
- return httpx.Response(500, request=request)
- state = self.state.get(user, JupyterState.LOGGED_OUT)
- assert state != JupyterState.LOGGED_OUT
- if self.delete_immediate:
- self.state[user] = JupyterState.LOGGED_IN
- else:
- now = datetime.now(tz=timezone.utc)
- self._delete_at[user] = now + timedelta(seconds=5)
- return httpx.Response(202, request=request)
-
- def create_session(self, request: httpx.Request) -> httpx.Response:
- user = self._get_user(request.headers["Authorization"])
- assert str(request.url).endswith(f"/user/{user}/api/sessions")
- assert user not in self.sessions
- if JupyterAction.CREATE_SESSION in self._fail.get(user, {}):
- return httpx.Response(500, request=request)
- state = self.state.get(user, JupyterState.LOGGED_OUT)
- assert state == JupyterState.LAB_RUNNING
- request_json = json.loads(request.content.decode("utf-8"))
- assert request_json["kernel"]["name"] == "LSST"
- assert request_json["name"] == "(no notebook)"
- assert request_json["type"] == "console"
- session = JupyterLabSession(
- username=user,
- session_id=uuid4().hex,
- kernel_id=uuid4().hex,
- websocket=AsyncMock(),
- logger=structlog.get_logger(),
- )
- self.sessions[user] = session
- return httpx.Response(
- 201,
- json={
- "id": session.session_id,
- "kernel": {"id": session.kernel_id},
- },
- request=request,
- )
-
- def delete_session(self, request: httpx.Request) -> httpx.Response:
- user = self._get_user(request.headers["Authorization"])
- session_id = self.sessions[user].session_id
- assert str(request.url).endswith(
- f"/user/{user}/api/sessions/{session_id}"
- )
- if JupyterAction.DELETE_SESSION in self._fail.get(user, {}):
- return httpx.Response(500, request=request)
- state = self.state.get(user, JupyterState.LOGGED_OUT)
- assert state == JupyterState.LAB_RUNNING
- del self.sessions[user]
- return httpx.Response(204, request=request)
-
- @staticmethod
- def _get_user(authorization: str) -> str:
- """Get the user from the Authorization header."""
- assert authorization.startswith("Bearer ")
- token = authorization.split(" ", 1)[1]
- user = urlsafe_b64decode(token[3:].split(".", 1)[0].encode())
- return user.decode()
-
-
-def mock_jupyter(mock_router: respx.Router) -> MockJupyter:
- """Set up a mock JupyterHub/Lab that always returns success.
-
- Currently only handles a lab spawn and then shutdown. Behavior will
- eventually be configurable.
- """
- mock = MockJupyter()
-
- mock_router.get(url_for_path("hub/login")).mock(side_effect=mock.login)
- mock_router.get(url_for_path("hub/spawn"))
- mock_router.post(url_for_path("hub/spawn")).mock(side_effect=mock.spawn)
-
- mock_router.get(
- url__regex=url_for_pattern(r"hub/spawn-pending/[^/]+$")
- ).mock(side_effect=mock.spawn_pending)
-
- mock_router.get(url__regex=url_for_pattern(r"hub/user/[^/]+/lab$")).mock(
- side_effect=mock.missing_lab
- )
-
- mock_router.get(url__regex=url_for_pattern(r"hub/api/users/[^/]+$")).mock(
- side_effect=mock.user
- )
-
- mock_router.get(
- url__regex=url_for_pattern(r"hub/api/users/[^/]+/server/progress$")
- ).mock(side_effect=mock.progress)
-
- mock_router.delete(
- url__regex=url_for_pattern(r"hub/api/users/[^/]+/server")
- ).mock(side_effect=mock.delete_lab)
-
- mock_router.get(url__regex=url_for_pattern(r"user/[^/]+/lab")).mock(
- side_effect=mock.lab
- )
-
- mock_router.post(
- url__regex=url_for_pattern(r"user/[^/]+/api/sessions")
- ).mock(side_effect=mock.create_session)
-
- mock_router.delete(
- url__regex=url_for_pattern(r"user/[^/]+/api/sessions/[^/]+$"),
- ).mock(side_effect=mock.delete_session)
-
- return mock
-
-
-class MockJupyterWebSocket(Mock):
- """Simulate the WebSocket connection in a JupyterLabSession.
-
- Note
- ----
- The methods are named the reverse of what you would expect. For example,
- ``send_json`` receives a message, and ``receive_json`` returns a message.
- This is so that this class can be used as a mock of an
- `~aiohttp.ClientWebSocketResponse`.
- """
-
- def __init__(self, user: str, session_id: str) -> None:
- super().__init__(spec=WebSocketClientProtocol)
- self.user = user
- self.session_id = session_id
- self._header: Optional[dict[str, Any]] = None
- self._code: Optional[str] = None
- self._state: dict[str, Any] = {}
-
- def __await__(self) -> MockJupyterWebSocket:
- return self
-
- async def __aenter__(self) -> MockJupyterWebSocket:
- return await self
-
- async def __aexit__(
- self, exc_type: Any, exc_value: Any, traceback: Any
- ) -> None:
- pass
-
- async def send(self, text_message: str) -> None:
- message = json.loads(text_message)
- assert message == {
- "header": {
- "username": self.user,
- "version": "5.0",
- "session": self.session_id,
- "msg_id": ANY,
- "msg_type": "execute_request",
- },
- "parent_header": {},
- "channel": "shell",
- "content": {
- "code": ANY,
- "silent": False,
- "store_history": False,
- "user_expressions": {},
- "allow_stdin": False,
- },
- "metadata": {},
- "buffers": {},
- }
- self._header = message["header"]
- self._code = message["content"]["code"]
-
- async def __aiter__(self) -> AsyncIterator[str]:
- assert self._header
- while True:
- if self._code == _GET_NODE:
- self._code = None
- yield json.dumps(
- {
- "msg_type": "stream",
- "parent_header": self._header,
- "content": {"text": "some-node"},
- }
- )
- elif self._code == "long_error_for_test()":
- self._code = None
- error = ""
- line = (
- "this is a single line of output to test trimming errors"
- )
- for i in range(int(3000 / len(line))):
- error += f"{line} #{i}\n"
- yield json.dumps(
- {
- "msg_type": "error",
- "parent_header": self._header,
- "content": {"traceback": error},
- }
- )
- elif self._code:
- try:
- output = StringIO()
- with redirect_stdout(output):
- exec(self._code, self._state)
- self._code = None
- yield json.dumps(
- {
- "msg_type": "stream",
- "parent_header": self._header,
- "content": {"text": output.getvalue()},
- }
- )
- except Exception:
- result = {
- "msg_type": "error",
- "parent_header": self._header,
- "content": {"traceback": format_exc()},
- }
- self._header = None
- yield json.dumps(result)
- else:
- result = {
- "msg_type": "execute_reply",
- "parent_header": self._header, # type: ignore
- "content": {"status": "ok"},
- }
- self._header = None
- yield json.dumps(result)
-
-
-def mock_jupyter_websocket(
- url: str, jupyter: MockJupyter
-) -> MockJupyterWebSocket:
- """Create a new mock ClientWebSocketResponse that simulates a lab."""
- match = re.search("/user/([^/]+)/api/kernels/([^/]+)/channels", url)
- assert match
- user = match.group(1)
- assert user
- session = jupyter.sessions[user]
- assert match.group(2) == session.kernel_id
- return MockJupyterWebSocket(user, session.session_id)
diff --git a/src/noteburst/jupyterclient/__init__.py b/tests/worker/__init__.py
similarity index 100%
rename from src/noteburst/jupyterclient/__init__.py
rename to tests/worker/__init__.py