diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cdcc26c5..4ba9e43e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -73,3 +73,53 @@ jobs: with: image: ${{ github.repository }} github_token: ${{ secrets.GITHUB_TOKEN }} + + docs: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Print GitHub event name + run: echo "${{ github.event_name }}" + + - name: Filter paths + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + docs: + - "docs/**" + - "src/mobu/**" + docsSpecific: + - "docs/**" + + - name: Install graphviz + if: steps.filter.outputs.docs == 'true' || github.event_name == 'workflow_dispatch' + run: sudo apt-get install graphviz + + - name: Build docs + if: steps.filter.outputs.docs == 'true' || github.event_name == 'workflow_dispatch' + uses: lsst-sqre/run-tox@v1 + with: + python-version: "3.12" + tox-envs: docs + tox-plugins: tox-uv + cache-key-prefix: docs + + # Upload docs: + # - on pushes to main if *any* documentation content might have changed + # - on workflow dispatches if any documentation content might have changed + # - on pushes to tickets/ branches if docs/ directory content changed + - name: Upload to LSST the Docs + uses: lsst-sqre/ltd-upload@v1 + with: + project: "mobu" + dir: "docs/_build/html" + username: ${{ secrets.LTD_USERNAME }} + password: ${{ secrets.LTD_PASSWORD }} + if: >- + (github.event_name == 'push' && github.ref_name == 'main' && steps.filter.outputs.docs == 'true') + || (github.event_name == 'workflow_dispatch') + || (github.event_name == 'pull_request' && startsWith(github.head_ref, 'tickets/') && steps.filter.outputs.docsSpecific == 'true') diff --git a/.gitignore b/.gitignore index f1289eb6..3a932431 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,7 @@ instance/ .scrapy # Sphinx documentation +docs/_static docs/_build/ # PyBuilder diff --git a/README.md b/README.md index 3c24d227..11b01846 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,7 @@ It attempts to simulate user interactions with Science Platform services continu It can be used for both monitoring and synthetic load testing. mobu is developed with the [Safir](https://safir.lsst.io/) framework. + +See [mobu.lsst.io](https://mobu.lsst.io) for full documentation. + + diff --git a/changelog.d/20240626_113149_danfuchs_mobu_in_ci.md b/changelog.d/20240626_113149_danfuchs_mobu_in_ci.md new file mode 100644 index 00000000..784682ef --- /dev/null +++ b/changelog.d/20240626_113149_danfuchs_mobu_in_ci.md @@ -0,0 +1,13 @@ + + +### Backwards-incompatible changes + +- The existing refresh functionality is now a GitHub app integration (from a simple webhook integration). This requires new Phalanx secrets to be sync'd, and a new GitHub app to be added to repos that want the functionality. Special care has been taken to not leave these checks in a forever-in-progress state, even in the case of (graceful) mobu shutdown/restart + +### New features + +- A GitHub app integration to generate GitHub actions checks for commits pushed to notebook repo branches that are part of active PRs. These checks trigger and report on a solitary Mobu run of the changed notebooks in the commit. + +### Other changes + +- Python 3.12.3 -> 3.12.4 diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 00000000..80eb0f81 --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,5 @@ +######## +REST API +######## + +This is a stub page for the API. diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..3fd6377e --- /dev/null +++ b/docs/conf.py @@ -0,0 +1 @@ +from documenteer.conf.guide import * diff --git a/docs/development/github.rst b/docs/development/github.rst new file mode 100644 index 00000000..e1eade73 --- /dev/null +++ b/docs/development/github.rst @@ -0,0 +1,58 @@ +########################### +Testing GitHub integrations +########################### + +The GitHub integrations can be tested locally by pointing your local mobu at the ``idfdev`` env, and using a services like https://smee.io to proxy GitHub webhooks to your local mobu. + +Test repo +========= +`This repo `__ has a bunch of different notebooks in a bunch of different directories, some of which intentionally throw exceptions. +It contains `a script `__ to update certain notebooks, conditionally updating the poison ones. +The `data-dev Mobu CI app `__ in the `lsst-sqre GitHub org `__, is currently installed and configured to work with this repo. + +smee.io +======= +You can use https://smee.io to proxy GitHub webhook requests from the data-dev Mobu CI GitHub app to your local mobu. + +#. Install the tool from [smee.io](https://smee.io/). +#. Start it up and point it at your one of local mobu's GitHub webhook endpoints (the CI endpoint in this example): + + .. code-block:: + + ❯ smee -p 8000 -P /mobu/github/ci/webhook + Forwarding https://smee.io/kTysHB50d4pgUmRN to http://127.0.0.1:8000/mobu/github/ci/webhook + +#. Configure the [data-dev GitHub Mobu CI app](https://github.com/organizations/lsst-sqre/settings/apps/mobu-ci-data-dev-lsst-cloud) to send webooks to the smee URL. +#. Run your local mobu against the ``idfdev`` env, as described :doc:`here `. +#. Point your local mobu at a local `Safir `__ . + + .. code-block:: diff + + index ce732db..ce2d693 100644 + --- a/requirements/main.in + +++ b/requirements/main.in + @@ -22,6 +22,6 @@ pydantic-settings + pyvo + pyyaml + -safir>=5.0.0 + +# safir>=5.0.0 + +-e /home/danfuchs/src/safir + shortuuid + structlog + +#. Patch your local Safir to handle the malformed requests that smee.io sends. + The requests sent by the smee proxy have ``:port`` suffixes in the ``X-Forwarded-For`` values. + Safir doesn't handle this (and I don't think it's Safir's fault; I _think_ the port should be in ``X-Forwarded-Port``), so you have to change Safir: + + .. code-block:: diff + + index 2a3f40c..7211241 100644 + --- a/src/safir/middleware/x_forwarded.py + +++ b/src/safir/middleware/x_forwarded.py + @@ -116,5 +116,5 @@ class XForwardedMiddleware: + return [ + ip_address(addr) + - for addr in (a.strip() for a in forwarded_for_str[0].split(",")) + + for addr, _ in (a.strip().split(':') for a in forwarded_for_str[0].split(",")) + if addr + ] diff --git a/docs/development/idfdev.rst b/docs/development/idfdev.rst new file mode 100644 index 00000000..828bab3e --- /dev/null +++ b/docs/development/idfdev.rst @@ -0,0 +1,72 @@ +########################## +Testing against ``idfdev`` +########################## + +You can run mobu locally while having all of the actual business run against services in ``idefdev`` (or any other environment). + + +#. Install the `1Password CLI `__. +#. Generate a personal `idfdev gafaelfawr token `__ generated with an ``admin:token`` scope. +#. Put this token in a ``data-dev.lsst.cloud personal token`` entry in your personal 1Password vault. +#. Run mobu locally with something like this shell script: + + .. code-block:: shell + + #!/usr/bin/env bash + + set -euo pipefail + + config_dir="/tmp/mobu_test" + ci_config_file="github.yaml" + ci_config_path="$config_dir/$ci_config_file" + autostart_config_file="autostart.yaml" + autostart_config_path="$config_dir/$autostart_config_file" + + mkdir -p "$config_dir" + + # Note: This whitespace must be actual chars! + cat <<- 'END' > "$ci_config_path" + users: + - username: bot-mobu-ci-local-1 + - username: bot-mobu-ci-local-2 + accepted_github_orgs: + - lsst-sqre + END + + # Note: This whitespace must be actual chars! + cat <<- 'END' > "$autostart_config_path" + - name: "my-test" + count: 1 + users: + - username: "bot-mobu-my-test-local" + scopes: + - "exec:notebook" + business: + type: "NotebookRunner" + options: + repo_url: "https://github.com/lsst-sqre/dfuchs-test-mobu.git" + repo_branch: "main" + max_executions: 10 + restart: true + END + + export MOBU_ENVIRONMENT_URL=https://data-dev.lsst.cloud + export MOBU_GAFAELFAWR_TOKEN=$(op read "op://Employee/data-dev.lsst.cloud personal token/credential") + export MOBU_AUTOSTART_PATH="$autostart_config_path" + export MOBU_LOG_LEVEL=debug + + # Don't set the MOBU_GITHUB_REFRESH* vars if you don't need that integration + export MOBU_GITHUB_REFRESH_ENABLED=true + export MOBU_GITHUB_REFRESH_APP_WEBHOOK_SECRET=$(op read "op://RSP data-dev.lsst.cloud/mobu/github-refresh-app-webhook-secret") + + # Don't set the MOBU_GITHUB_REFRESH* vars if you don't need that integration + export MOBU_GITHUB_CI_APP_ENABLED=true + export MOBU_GITHUB_CI_APP_WEBHOOK_SECRET=$(op read "op://RSP data-dev.lsst.cloud/mobu/github-ci-app-webhook-secret") + export MOBU_GITHUB_CI_APP_ID=$(op read "op://RSP data-dev.lsst.cloud/mobu/github-ci-app-id") + export MOBU_GITHUB_CI_APP_PRIVATE_KEY=$(op read "op://RSP data-dev.lsst.cloud/mobu/github-ci-app-private-key" | base64 -d) + + # Don't set MOBU_GITHUB_CONFIG_PATH if you don't need any of the GitHub integrations. + export MOBU_GITHUB_CONFIG_PATH="$ci_config_path" + + uvicorn mobu.main:app 2>&1 + diff --git a/docs/development/index.rst b/docs/development/index.rst new file mode 100644 index 00000000..f5a838fb --- /dev/null +++ b/docs/development/index.rst @@ -0,0 +1,10 @@ +########### +Development +########### + +Here are some guides on developing and testing mobu. + +.. toctree:: + + idfdev + github diff --git a/docs/documenteer.toml b/docs/documenteer.toml new file mode 100644 index 00000000..a4a13c47 --- /dev/null +++ b/docs/documenteer.toml @@ -0,0 +1,12 @@ +[project] +title = "Mobu" +copyright = "2015-2024 Association of Universities for Research in Astronomy, Inc. (AURA)" + +[project.python] +package = "mobu" + +[project.openapi] +openapi_path = "_static/openapi.json" + +[project.openapi.generator] +function = "mobu.main:create_openapi" diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..3c5b06ea --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,40 @@ +.. toctree:: + :maxdepth: 1 + :hidden: + + user_guide/index + operations/index + development/index + api + +#### +Mobu +#### + +mobu (short for "monkey business") is a continous integration testing framework for the `Rubin Science Platform `__ . +It attempts to simulate user interactions with Science Platform services continuously, recording successes and failures and optionally reporting failures to a Slack channel via a Slack incoming webhook. +It runs some number of "monkeys" that simulate a random user of the Science Platform. +Those monkeys are organized into "flocks" that share a single configuration across all of the monkeys. +It can be used for both monitoring and synthetic load testing. + +mobu is on github at https://github.com/lsst-sqre/mobu. + +.. grid:: 3 + + .. grid-item-card:: User Guide + :link: user_guide/index + :link-type: doc + + Learn how to configure mobu to run your run and test your code. + + .. grid-item-card:: Operations + :link: operations/index + :link-type: doc + + Learn how to add mobu to new environments and add new integrations to mobu. + + .. grid-item-card:: Development + :link: operations/index + :link-type: doc + + Learn how to add contribute to the mobu codebase. diff --git a/docs/operations/index.rst b/docs/operations/index.rst new file mode 100644 index 00000000..47f17c74 --- /dev/null +++ b/docs/operations/index.rst @@ -0,0 +1,120 @@ +########## +Operations +########## + +GitHub integration +================== + +Each integration has as GitHub application created in the `lsst-sqre org `__ for every environment in which it is enabled. + +All of the applications: + +* `mobu refresh (data-dev.lsst.cloud) `__ +* `mobu CI (data-dev.lsst.cloud) `__ + +GitHub application configuration +================================ + +To enable the GitHub integrations for another mobu env, you have to create a new GitHub application and sync Phalanx secrets. + +Refresh app +----------- + +Create a new GitHub app +~~~~~~~~~~~~~~~~~~~~~~~ + + +#. Click the ``New GitHub App`` button in the `lsst-sqre org Developer Settings apps page `__. + +#. Name it ``mobu refresh ()``. + +#. Make sure the ``Active`` checkbox is checked in the ``Webhook`` section. + +#. Enter ``https:///mobu/github/refresh/webhook`` in the ``Webhook URL`` input. +#. Generate a strong password to use as the webhook secret. +#. Store this in the ``SQuaRE`` vault in the ``LSST IT`` 1Password account in an item named ``mobu GitHub refresh app webhook secret ()``. +#. Get this into the Phalanx secret store for that env under the key: ``github-refresh-app-webhook-secret`` (`this process `__ is different for different envs). +#. Enter this secret in the ``Webhook secret (optional)`` box in the GitHub App config. +#. Select ``Read-only`` in the dropdown of the ``Contents`` access category in the ``Repository Permissions`` section. +#. Check the ``Push`` checkbox in the ``Subscribe to events`` section. +#. Select the ``Any account`` radio button in the ``Where can this GitHub App be installed?`` section. +#. Click the ``Create GitHub App`` button. +#. Do the `Phalanx configuration <#phalanx-configuration>`__. + +Install the app for a repo +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#. Go to new app’s homepage (something like https://github.com/apps/mobu-refresh-usdfdev). +#. Click the ``Install`` button. +#. Select the ``Only select repositories`` radio button. +#. Select the repo in the dropdown. +#. Click ``Install``. + +CI app +------ + +Create a new GitHub app +~~~~~~~~~~~~~~~~~~~~~~~ + +#. Click the ``New GitHub App`` button in the `lsst-sqre org Developer Settings apps page `__. +#. Name it ``mobu CI ()``. +#. Make sure the ``Active`` checkbox is checked in the ``Webhook`` section. +#. Enter ``https:///mobu/github/ci/webhook`` in the ``Webhook URL`` input. +#. Generate a strong password to use as the webhook secret. +#. Store this in the ``SQuaRE`` vault in the ``LSST IT`` 1Password account in an item named ``mobu GitHub CI app webhook secret ()``. +#. Get this into the Phalanx secret store for that env under the key: ``github-ci-app-webhook-secret`` (`this process `__ is different for different envs). +#. Enter this secret in the ``Webhook secret (optional)`` box in the GitHub App config. +#. Select ``Read and Write`` in the dropdown of the ``Checks`` access category in the ``Repository Permissions`` section. +#. Select ``Read-only`` in the dropdown of the ``Contents`` access category in the ``Repository Permissions`` section. +#. Check the ``Check suite`` and ``Check run`` checkboxes in the ``Subscribe to events`` section. +#. Select the ``Any account`` radio button in the ``Where can this GitHub App be installed?`` section. +#. Click the ``Create GitHub App`` button. +#. Find the ``App ID`` (an integer) in the ``About`` section. Get this into the Phalanx secret store for that env under the key: ``github-ci-app-id`` (`this process `__ is different for different envs). +#. Click the ``Generate a private key`` button in the ``Private keys`` section. +#. Store this private key in the ``SQuaRE`` vault in the ``LSST IT`` 1Password account in an item named ``mobu GitHub CI app private key ()``. +#. Get this into the Phalanx secret store for that env under the key: ``github-ci-app-private-key`` (`this process `__ is different for different envs). +#. Do the `Phalanx configuration <#phalanx-configuration>`__. + +Install the app for a repo +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#. Go to new app’s homepage (something like https://github.com/apps/mobu-refresh-usdfdev). +#. Click the ``Install`` button. +#. Select the ``Only select repositories`` radio button. +#. Select the repo in the dropdown. +#. Click ``Install``. + +Phalanx configuration +===================== + +The GitHub integrations each need to be explicitly enabled in Phalanx for a given environment. +If an integration is not enabled, then the webhook route for that integration will not be mounted, GitHub webhook requests will get ``404`` responses. +To enable these integrations for an environment, set these values to ``true``: + +* ``config.githubRefreshAppEnabled`` +* ``config.githubCiAppEnabled`` + +If you want to enable either GitHub integration in a given environment, you also need to add a ``config.github`` section to that env’s values in Mobu. +That needs to be a dict with at ``users`` and ``accepted_github_orgs`` entries. +It should look something like this: + +.. code:: yaml + + config: + github: + accepted_github_orgs: + - lsst-sqre + users: + - username: "bot-mobu-ci-user-1" + uidnumber: 123 + gidnumber: 456 + - username: "bot-mobu-ci-user-2" + uidnumber: 789 + gidnumber: 876 + +The organization of any repo that uses any of the GitHub integrations in an env must be added to the ``accepted_github_orgs`` list, otherwise Github webhook requests will get ``403`` responses. + +The ``users`` list follows the same rules as the ``users`` list in a flock autostart config. +The usernames must all start with ``bot-mobu``. +In envs with Firestore integration, you only need to specify ``username``. +In envs without it, you need to ensure that users are manually provisioned, and then you need all three of ``username``, ``uidnumber``, and ``gidnumber``. diff --git a/docs/user_guide/flocks.rst b/docs/user_guide/flocks.rst new file mode 100644 index 00000000..08345014 --- /dev/null +++ b/docs/user_guide/flocks.rst @@ -0,0 +1,164 @@ +#################### +Managing mobu flocks +#################### + +Mobu calls each test runner a "monkey" and organizes them into groups called "flocks." +You can get a list of flocks from the mobu API. +For example, on the IDF production deployment, go to: + +`https://data.lsst.cloud/mobu/summary `_ + +Flocks can be also manipulated through the API. +For example, to stop a noisy flock running on ``data.lsst.cloud`` while troubleshooting is in progress, first obtain a token with ``exec:admin`` scope from the authentication service, and then: + +.. code-block:: bash + + curl -H 'Authorization: bearer ' -X DELETE https://data.lsst.cloud/mobu/flocks/tutorial + +Flock configuration +=================== + +Configuring mobu consists primarily of defining the flocks of monkeys that it should run. +This is done by setting the ``autostart`` key in the ``values-*.yaml`` file for that deployment to a list of flock definitions. +The definition of a flock must follow the same schema as a ``PUT`` to the ``/mobu/flocks`` route to create a new flock via the API. +Complete documentation is therefore available at the ``/mobu/redoc`` route on a given deployment. +This is just an overview of the most common configurations. + +Simple configuration +-------------------- + +Here is a simple configuration with a single flock that tests the Notebook Aspect by spawning a pod, running some Python, and then destroying the pod again: + +.. code-block:: yaml + + autostart: + - name: "python" + count: 1 + users: + - username: "bot-mobu-user" + scopes: ["exec:notebook"] + business: + type: "JupyterPythonLoop" + restart: true + options: + max_executions: 1 + code: "print(1+1)" + +Important points to note here: + +* The ``autostart`` key takes a list of flocks of monkeys. + Each one must have a ``name`` (which controls the URL for that flock under ``/mobu/flocks`` once it has been created) and a ``count`` key specifying how many monkeys will be performing this test. + +* Users must be defined for each monkey. + There are two ways to do this: specifying a list of users equal to the number of monkeys being run, or providing a specification for users that is used to programmatically generate usernames, UIDs, and GIDs. + An example of the latter will be given below. + Here, this specifies a single user with the name ``bot-mobu-user``. + Usernames must begin with ``bot-``. + Neither a UID nor a GID is specified, which means that Gafaelfawr has to be ble to generate UIDs and GIDs on the fly. + This configuration will therefore only work if this deployment enables Firestore for UID and GID generation, and enables synthesizing user private groups. + +* If the monkey user will need additional scopes, they must be specified. + Here, the required scope is ``exec:notebook``, which allows spawning Notebooks. + More scopes would be needed if the monkey were running notebooks that interacted with other applications. + +* The ``business.type`` key specifies the type of test to perform. + Here, ``JupyterPythonLoop`` just runs a small bit of Python through the Jupyter lab API after spawning a lab pod. + ``options.code`` can be used to specify the Python code to be run in the loop. + See the full mobu documentation for more details. + +* ``restart: true`` tells mobu to shut down and respawn the pod if there is any failure. + The default is to attempt to keep using the same pod despite the failure. + +Testing with notebooks +---------------------- + +Here is a more complex example that runs a set of notebooks as a test: + +.. code-block:: yaml + + autostart: + - name: "firefighter" + count: 1 + users: + - username: "bot-mobu-recommended" + uidnumber: 74768 + gidnumber: 74768 + scopes: + - "exec:notebook" + - "exec:portal" + - "read:image" + - "read:tap" + business: + type: "NotebookRunner" + options: + repo_url: "https://github.com/lsst-sqre/system-test.git" + repo_branch: "prod" + exclude_dirs: ["some/experiment/dir", "another/dir"] + max_executions: 1 + restart: true + +Here, note that the UID and primary GID for the user are specified, so this example will work in deployments that do not use Firestore and synthesized user private groups. + +This uses the business ``NotebookRunner`` instead, which checks out a Git repository and runs all notebooks in that repository, at the top level and any directories and subdirectories. + +The repository URL and branch are configured in ``options``. +``options.max_executions: 1`` tells mobu to shut down and respawn the pod after each notebook. +This exercises pod spawning more frequently, but does not test the lab's ability to run a long series of notebooks. +One may wish to run multiple flocks in a given environment with different configurations for ``max_executions``. +``options.exclude_dirs`` tells mobu to not excecute any notebooks in those directories or any descendant directories. +Those directories are relative to the repo root. + +These notebooks need more scopes, so those scopes are specified. + +Here is a different example that runs multiple monkeys in a flock: + +.. code-block:: yaml + + autostart: + - name: "firefighter" + count: 5 + user_spec: + username_prefix: "bot-mobu-recommended" + uid_start: 74768 + gid_start: 74768 + scopes: + - "exec:notebook" + - "exec:portal" + - "read:image" + - "read:tap" + business: + type: "NotebookRunner" + options: + repo_url: "https://github.com/lsst-sqre/system-test.git" + repo_branch: "prod" + max_executions: 1 + restart: true + +This is almost identical except that it specifies five monkeys and provides a specification for creating the users instead of specifying each user. +The users will be assigned consecutive UIDs and GIDs starting with the specified ``uid_start`` and ``gid_start``. +The usernames will be formed by adding consecutive digits to the end of the ``username_prefix``. + +Testing TAP +----------- + +Here is an example of testing the TAP application: + +.. code-block:: yaml + + autostart: + - name: "tap" + count: 1 + users: + - username: "bot-mobu-tap" + uidnumber: 74775 + gidnumber: 74775 + scopes: ["read:tap"] + business: + type: "TAPQueryRunner" + restart: true + options: + sync: true + query_set: "dp0.2" + +Note that ``business.type`` is set to ``TAPQueryRunner`` instead. +``options.sync`` can choosen between sync and async queries, and ``options.query_set`` can be used to specify the query set to run. diff --git a/docs/user_guide/github/ci.rst b/docs/user_guide/github/ci.rst new file mode 100644 index 00000000..bcc6aefd --- /dev/null +++ b/docs/user_guide/github/ci.rst @@ -0,0 +1,66 @@ +########################################## +Run notebooks in Mobu as a GitHub CI check +########################################## + +Problem + You have a GitHub repo filled with Python notebooks. + You’ve already configured Mobu to run a flock that executes these notebooks. + You want to make sure that any changes to these notebooks don’t cause them to break when they run in Mobu, but you don’t want to have to commit the possibly-broken changes just to get Mobu to run them to test the changes. + +Solution + Enable a GitHub app for your repo, and Mobu will create a GitHub Actions + check that runs changed notebooks in Mobu on any commit associated with + a pull request! + +.. _configuration-1: + +Configuration +============= + +There is a ``mobu CI ()`` GitHub app for every non-production environment that runs Mobu (Except environments behind a VPN). +For every environment in which you want to run your changed notebooks on every PR commit, you have to install the app in your repo's organization and enable the app for your repo. + +Install the app +--------------- +If it’s not already installed, that is. + +#. Install that environment’s ``mobu CI`` app in your repo’s GitHub organization. + Someone with appropriate permissions can do that from the `app’s homepage <#mobu-ci-github-app-urls>`__. +#. Add your organization to the ``accetped_github_orgs`` list in the Mobu configuration in Phalanx for the matching env. + +Enable the app for your repo +---------------------------- + +#. Go to your repo’s organization settings page in GitHub, and go to the “GitHub Apps” page in the “Third-party Access” section in the left sidebar. + `Here `__ is that page for the ``lsst-sqre`` organization. +#. Click the ``Configure`` button in the ``mobu CI ()`` row. +#. In the “Repository access” section, click the “Select repositories” dropdown and add your repository. + +Optional configuration +====================== + +You can have mobu ignore changed notebooks in certain directories in these CI checks by listing them in a file named ``mobu.yaml`` at the root of your repo, like this: + +.. code:: yaml + + exclude_dirs: + - somedir + - some/other/dir + +With this configuration, no notebooks in the ``somedir``, or ``some/other/dir`` directories, or any of their descendant directories, will be executed, even if they changed in the commit. + +Troubleshooting +=============== + +There is a small chance that a GitHub check could get stuck in a forever-in-progress state for a given commit if the stars align in a very specific way when mobu restarts. +If this happens, you can push a commit to your branch, and it will start a new check run. +If you don’t have any actual changes to commit, you can push an empty commit like this:: + + git commit --allow-empty -m "Empty commit" + +You can squash that commit later if you want a clean history. + +Mobu CI GitHub app URLs +======================= + +- `data-dev.lsst.cloud `__ diff --git a/docs/user_guide/github/index.rst b/docs/user_guide/github/index.rst new file mode 100644 index 00000000..fc038719 --- /dev/null +++ b/docs/user_guide/github/index.rst @@ -0,0 +1,17 @@ +################## +GitHub integration +################## +Mobu offers two integrations with GitHub: + +* Automatic notebook refreshing in flocks +* GitHub Actions checks for PR commits + +Each is enabled by enabling a GitHub application on a repo full of notebooks. +There is a separate GitHub application for each integration in each environment. +This lets you enable these integrations for different combinations of environments. +For example, you can enable the auto-refresh integration in ``idfdev``, ``idfint``, ``usdfdev``, ``usdfint``, and ``usdfprod``, but the CI integration only in ``idfint`` and ``usdfint``. + +.. toctree:: + + refresh + ci diff --git a/docs/user_guide/github/refresh.rst b/docs/user_guide/github/refresh.rst new file mode 100644 index 00000000..5b275b1b --- /dev/null +++ b/docs/user_guide/github/refresh.rst @@ -0,0 +1,40 @@ +############################ +Auto-refresh notebook flocks +############################ + +Problem + You have a GitHub repo filled with Python notebooks. + You’ve already configured Mobu to run a flock that executes these notebooks. + But every time you commit changes to the notebooks in this repo, you have to restart Mobu to get it to pick up the changes! + +Solution + Enable a GitHub app for your repo, and Mobu will automatically pick up any changes. + +Configuration +============= + +There is a ``mobu refresh ()`` GitHub app for every environment that runs Mobu (Except environments behind a VPN). +For every environment in which you want your repo to auto refresh, you have to install the app in your repo's organization, and enable the app for your repo. + +Install the app +--------------- +If it's not already installed, that is. + +#. Have a Mobu autorun flock configured and running. +#. Install that environment’s ``mobu refresh`` app in your repo’s GitHub organization. + Someone with appropriate permissions can do that from the `app’s homepage <#mobu-refresh-github-app-urls>`__. +#. Add your organization to the ``accetped_github_orgs`` list in the Mobu configuration in Phalanx for the matching env. + +Enable the app for your repo +---------------------------- + +#. Go to your repo’s organization settings page in GitHub, and go to the “GitHub Apps” page in the “Third-party Access” section in the left sidebar. + `Here `__ is that page for the ``lsst-sqre`` organization. +#. Click the ``Configure`` button in the ``mobu refresh ()`` row. +#. In the “Repository access” section, click the “Select repositories” dropdown and add your repository. + +Mobu refresh GitHub app URLs +============================ + +- `data-dev.lsst.cloud `__ + diff --git a/docs/user_guide/index.rst b/docs/user_guide/index.rst new file mode 100644 index 00000000..18c92f49 --- /dev/null +++ b/docs/user_guide/index.rst @@ -0,0 +1,9 @@ +########## +User Guide +########## + +.. toctree:: + + flocks + github/index + diff --git a/pyproject.toml b/pyproject.toml index 60285141..b18e3dde 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ dynamic = ["version"] monkeyflocker = "monkeyflocker.cli:main" [project.urls] -Homepage = "https://github.com/lsst-sqre/mobu" +Homepage = "https://mobu.lsst.io" Source = "https://github.com/lsst-sqre/mobu" [build-system] @@ -120,6 +120,9 @@ python_files = ["tests/*.py", "tests/*/*.py"] [tool.ruff] line-length = 79 target-version = "py312" +exclude = [ + "docs/**", +] [tool.ruff.lint] ignore = [ diff --git a/requirements/dev.in b/requirements/dev.in index 0f37fff4..5c29d55a 100644 --- a/requirements/dev.in +++ b/requirements/dev.in @@ -10,6 +10,7 @@ # Testing asgi-lifespan coverage[toml] +documenteer[guide] mypy pre-commit pytest diff --git a/requirements/dev.txt b/requirements/dev.txt index 40527b19..2e7f1e18 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -1,5 +1,15 @@ # This file was autogenerated by uv via the following command: # uv pip compile --generate-hashes --output-file requirements/dev.txt requirements/dev.in +alabaster==0.7.16 \ + --hash=sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65 \ + --hash=sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92 + # via sphinx +annotated-types==0.7.0 \ + --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \ + --hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89 + # via + # -c requirements/main.txt + # pydantic anyio==4.4.0 \ --hash=sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94 \ --hash=sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7 @@ -10,10 +20,26 @@ asgi-lifespan==2.1.0 \ --hash=sha256:5e2effaf0bfe39829cf2d64e7ecc47c7d86d676a6599f7afba378c31f5e3a308 \ --hash=sha256:ed840706680e28428c01e14afb3875d7d76d3206f3d5b2f2294e059b5c23804f # via -r requirements/dev.in +asttokens==2.4.1 \ + --hash=sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24 \ + --hash=sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0 + # via stack-data attrs==23.2.0 \ --hash=sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30 \ --hash=sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1 - # via scriv + # via + # jsonschema + # jupyter-cache + # referencing + # scriv +babel==2.15.0 \ + --hash=sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb \ + --hash=sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413 + # via sphinx +beautifulsoup4==4.12.3 \ + --hash=sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051 \ + --hash=sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed + # via pydata-sphinx-theme certifi==2024.6.2 \ --hash=sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516 \ --hash=sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56 @@ -126,11 +152,17 @@ click==8.1.7 \ # via # -c requirements/main.txt # click-log + # documenteer + # jupyter-cache # scriv click-log==0.4.0 \ --hash=sha256:3970f8570ac54491237bcdb3d8ab5e3eef6c057df29f8c3d1151a51a9c23b975 \ --hash=sha256:a43e394b528d52112af599f2fc9e4b7cf3c15f94e53581f74fa6867e68c91756 # via scriv +comm==0.2.2 \ + --hash=sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e \ + --hash=sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3 + # via ipykernel coverage==7.5.4 \ --hash=sha256:018a12985185038a5b2bcafab04ab833a9a0f2c59995b3cec07e10074c78635f \ --hash=sha256:02ff6e898197cc1e9fa375581382b72498eb2e6d5fc0b53f03e496cfee3fac6d \ @@ -187,14 +219,134 @@ coverage==7.5.4 \ # via # -r requirements/dev.in # pytest-cov +debugpy==1.8.2 \ + --hash=sha256:0600faef1d0b8d0e85c816b8bb0cb90ed94fc611f308d5fde28cb8b3d2ff0fe3 \ + --hash=sha256:1523bc551e28e15147815d1397afc150ac99dbd3a8e64641d53425dba57b0ff9 \ + --hash=sha256:15bc2f4b0f5e99bf86c162c91a74c0631dbd9cef3c6a1d1329c946586255e859 \ + --hash=sha256:16c8dcab02617b75697a0a925a62943e26a0330da076e2a10437edd9f0bf3755 \ + --hash=sha256:16e16df3a98a35c63c3ab1e4d19be4cbc7fdda92d9ddc059294f18910928e0ca \ + --hash=sha256:2cbd4d9a2fc5e7f583ff9bf11f3b7d78dfda8401e8bb6856ad1ed190be4281ad \ + --hash=sha256:3f8c3f7c53130a070f0fc845a0f2cee8ed88d220d6b04595897b66605df1edd6 \ + --hash=sha256:40f062d6877d2e45b112c0bbade9a17aac507445fd638922b1a5434df34aed02 \ + --hash=sha256:5a019d4574afedc6ead1daa22736c530712465c0c4cd44f820d803d937531b2d \ + --hash=sha256:5d3ccd39e4021f2eb86b8d748a96c766058b39443c1f18b2dc52c10ac2757835 \ + --hash=sha256:62658aefe289598680193ff655ff3940e2a601765259b123dc7f89c0239b8cd3 \ + --hash=sha256:7ee2e1afbf44b138c005e4380097d92532e1001580853a7cb40ed84e0ef1c3d2 \ + --hash=sha256:7f8d57a98c5a486c5c7824bc0b9f2f11189d08d73635c326abef268f83950326 \ + --hash=sha256:8a13417ccd5978a642e91fb79b871baded925d4fadd4dfafec1928196292aa0a \ + --hash=sha256:95378ed08ed2089221896b9b3a8d021e642c24edc8fef20e5d4342ca8be65c00 \ + --hash=sha256:acdf39855f65c48ac9667b2801234fc64d46778021efac2de7e50907ab90c634 \ + --hash=sha256:bd11fe35d6fd3431f1546d94121322c0ac572e1bfb1f6be0e9b8655fb4ea941e \ + --hash=sha256:c78ba1680f1015c0ca7115671fe347b28b446081dada3fedf54138f44e4ba031 \ + --hash=sha256:cf327316ae0c0e7dd81eb92d24ba8b5e88bb4d1b585b5c0d32929274a66a5210 \ + --hash=sha256:d3408fddd76414034c02880e891ea434e9a9cf3a69842098ef92f6e809d09afa \ + --hash=sha256:e24ccb0cd6f8bfaec68d577cb49e9c680621c336f347479b3fce060ba7c09ec1 \ + --hash=sha256:f179af1e1bd4c88b0b9f0fa153569b24f6b6f3de33f94703336363ae62f4bf47 + # via ipykernel +decorator==5.1.1 \ + --hash=sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330 \ + --hash=sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186 + # via ipython distlib==0.3.8 \ --hash=sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784 \ --hash=sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64 # via virtualenv +documenteer==1.3.0 \ + --hash=sha256:5930e3c6ef9ee1b7c49db280925a34451bd4b7d1dd9c9601f690d700e2337010 \ + --hash=sha256:b598b415d5662ae2b7ee3e17a0c5ed6b99dbe93d4442e314e892277624040a78 + # via -r requirements/dev.in +docutils==0.21.2 \ + --hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \ + --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2 + # via + # documenteer + # myst-parser + # pybtex-docutils + # pydata-sphinx-theme + # sphinx + # sphinx-jinja + # sphinx-prompt + # sphinxcontrib-bibtex +executing==2.0.1 \ + --hash=sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147 \ + --hash=sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc + # via stack-data +fastjsonschema==2.20.0 \ + --hash=sha256:3d48fc5300ee96f5d116f10fe6f28d938e6008f59a6a025c2649475b87f76a23 \ + --hash=sha256:5875f0b0fa7a0043a91e93a9b8f793bcbbba9691e7fd83dca95c28ba26d21f0a + # via nbformat filelock==3.15.4 \ --hash=sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb \ --hash=sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7 # via virtualenv +gitdb==4.0.11 \ + --hash=sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4 \ + --hash=sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b + # via gitpython +gitpython==3.1.43 \ + --hash=sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c \ + --hash=sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff + # via documenteer +greenlet==3.0.3 \ + --hash=sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67 \ + --hash=sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6 \ + --hash=sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257 \ + --hash=sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4 \ + --hash=sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676 \ + --hash=sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61 \ + --hash=sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc \ + --hash=sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca \ + --hash=sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7 \ + --hash=sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728 \ + --hash=sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305 \ + --hash=sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6 \ + --hash=sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379 \ + --hash=sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414 \ + --hash=sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04 \ + --hash=sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a \ + --hash=sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf \ + --hash=sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491 \ + --hash=sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559 \ + --hash=sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e \ + --hash=sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274 \ + --hash=sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb \ + --hash=sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b \ + --hash=sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9 \ + --hash=sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b \ + --hash=sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be \ + --hash=sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506 \ + --hash=sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405 \ + --hash=sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113 \ + --hash=sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f \ + --hash=sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5 \ + --hash=sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230 \ + --hash=sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d \ + --hash=sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f \ + --hash=sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a \ + --hash=sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e \ + --hash=sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61 \ + --hash=sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6 \ + --hash=sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d \ + --hash=sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71 \ + --hash=sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22 \ + --hash=sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2 \ + --hash=sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3 \ + --hash=sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067 \ + --hash=sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc \ + --hash=sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881 \ + --hash=sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3 \ + --hash=sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e \ + --hash=sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac \ + --hash=sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53 \ + --hash=sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0 \ + --hash=sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b \ + --hash=sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83 \ + --hash=sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41 \ + --hash=sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c \ + --hash=sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf \ + --hash=sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da \ + --hash=sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33 + # via sqlalchemy h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -225,21 +377,88 @@ idna==3.7 \ # anyio # httpx # requests +imagesize==1.4.1 \ + --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \ + --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a + # via sphinx +importlib-metadata==8.0.0 \ + --hash=sha256:15584cf2b1bf449d98ff8a6ff1abef57bf20f3ac6454f431736cd3e660921b2f \ + --hash=sha256:188bd24e4c346d3f0a933f275c2fec67050326a856b9a359881d7c2a697e8812 + # via + # jupyter-cache + # myst-nb iniconfig==2.0.0 \ --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \ --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 # via pytest +ipykernel==6.29.4 \ + --hash=sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da \ + --hash=sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c + # via myst-nb +ipython==8.25.0 \ + --hash=sha256:53eee7ad44df903a06655871cbab66d156a051fd86f3ec6750470ac9604ac1ab \ + --hash=sha256:c6ed726a140b6e725b911528f80439c534fac915246af3efc39440a6b0f9d716 + # 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 # -c requirements/main.txt + # myst-parser # scriv + # sphinx + # sphinx-jinja + # sphinxcontrib-redoc +jsonschema==4.22.0 \ + --hash=sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7 \ + --hash=sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802 + # via + # nbformat + # sphinxcontrib-redoc +jsonschema-specifications==2023.12.1 \ + --hash=sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc \ + --hash=sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c + # via jsonschema +jupyter-cache==1.0.0 \ + --hash=sha256:594b1c4e29b488b36547e12477645f489dbdc62cc939b2408df5679f79245078 \ + --hash=sha256:d0fa7d7533cd5798198d8889318269a8c1382ed3b22f622c09a9356521f48687 + # via myst-nb +jupyter-client==8.6.2 \ + --hash=sha256:2bda14d55ee5ba58552a8c53ae43d215ad9868853489213f37da060ced54d8df \ + --hash=sha256:50cbc5c66fd1b8f65ecb66bc490ab73217993632809b6e505687de18e9dea39f + # 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.3 \ + --hash=sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048 \ + --hash=sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79 + # via markdown-it-py markdown-it-py==3.0.0 \ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb # via # -c requirements/main.txt + # documenteer + # mdit-py-plugins + # myst-parser # scriv markupsafe==2.1.5 \ --hash=sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf \ @@ -305,45 +524,82 @@ markupsafe==2.1.5 \ # via # -c requirements/main.txt # jinja2 +matplotlib-inline==0.1.7 \ + --hash=sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90 \ + --hash=sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca + # via + # ipykernel + # ipython +mdit-py-plugins==0.4.1 \ + --hash=sha256:1020dfe4e6bfc2c79fb49ae4e3f5b297f5ccd20f010187acc52af2921e27dc6a \ + --hash=sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c + # via myst-parser mdurl==0.1.2 \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba # via # -c requirements/main.txt # markdown-it-py -mypy==1.10.0 \ - --hash=sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061 \ - --hash=sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99 \ - --hash=sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de \ - --hash=sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a \ - --hash=sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9 \ - --hash=sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec \ - --hash=sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1 \ - --hash=sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131 \ - --hash=sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f \ - --hash=sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821 \ - --hash=sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5 \ - --hash=sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee \ - --hash=sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e \ - --hash=sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746 \ - --hash=sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2 \ - --hash=sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0 \ - --hash=sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b \ - --hash=sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53 \ - --hash=sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30 \ - --hash=sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda \ - --hash=sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051 \ - --hash=sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2 \ - --hash=sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7 \ - --hash=sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee \ - --hash=sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727 \ - --hash=sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976 \ - --hash=sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4 +mypy==1.10.1 \ + --hash=sha256:0cd62192a4a32b77ceb31272d9e74d23cd88c8060c34d1d3622db3267679a5d9 \ + --hash=sha256:1b3a2ffce52cc4dbaeee4df762f20a2905aa171ef157b82192f2e2f368eec05d \ + --hash=sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0 \ + --hash=sha256:2189ff1e39db399f08205e22a797383613ce1cb0cb3b13d8bcf0170e45b96cc3 \ + --hash=sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3 \ + --hash=sha256:37fd87cab83f09842653f08de066ee68f1182b9b5282e4634cdb4b407266bade \ + --hash=sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31 \ + --hash=sha256:51a46974340baaa4145363b9e051812a2446cf583dfaeba124af966fa44593f7 \ + --hash=sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e \ + --hash=sha256:5cc3ca0a244eb9a5249c7c583ad9a7e881aa5d7b73c35652296ddcdb33b2b9c7 \ + --hash=sha256:604282c886497645ffb87b8f35a57ec773a4a2721161e709a4422c1636ddde5c \ + --hash=sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b \ + --hash=sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e \ + --hash=sha256:6be84c06e6abd72f960ba9a71561c14137a583093ffcf9bbfaf5e613d63fa531 \ + --hash=sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04 \ + --hash=sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a \ + --hash=sha256:8addf6313777dbb92e9564c5d32ec122bf2c6c39d683ea64de6a1fd98b90fe37 \ + --hash=sha256:901c89c2d67bba57aaaca91ccdb659aa3a312de67f23b9dfb059727cce2e2e0a \ + --hash=sha256:97a131ee36ac37ce9581f4220311247ab6cba896b4395b9c87af0675a13a755f \ + --hash=sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84 \ + --hash=sha256:a2cbc68cb9e943ac0814c13e2452d2046c2f2b23ff0278e26599224cf164e78d \ + --hash=sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f \ + --hash=sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a \ + --hash=sha256:c2ae450d60d7d020d67ab440c6e3fae375809988119817214440033f26ddf7bf \ + --hash=sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7 \ + --hash=sha256:e36f229acfe250dc660790840916eb49726c928e8ce10fbdf90715090fe4ae02 \ + --hash=sha256:fe85ed6836165d52ae8b88f99527d3d1b2362e0cb90b005409b8bed90e9059b3 # via -r requirements/dev.in mypy-extensions==1.0.0 \ --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \ --hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782 # via mypy +myst-nb==1.1.0 \ + --hash=sha256:0ac29b2a346f9a1257edbfb5d6c47d528728a37e6b9438903c2821f69fda9235 \ + --hash=sha256:9278840e844f5d780b5acc5400cbf63d97caaccf8eb442a55ebd9a03e2522d5e + # via documenteer +myst-parser==3.0.1 \ + --hash=sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1 \ + --hash=sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87 + # 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 @@ -353,12 +609,25 @@ packaging==24.1 \ --hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124 # via # -c requirements/main.txt + # ipykernel + # pydata-sphinx-theme # pytest # pytest-sugar + # sphinx +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.2.2 \ --hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \ --hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3 - # via virtualenv + # via + # jupyter-core + # virtualenv pluggy==1.5.0 \ --hash=sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1 \ --hash=sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669 @@ -367,6 +636,152 @@ pre-commit==3.7.1 \ --hash=sha256:8ca3ad567bc78a4972a3f1a477e94a79d4597e8140a6e0b651c5e33899c3654a \ --hash=sha256:fae36fd1d7ad7d6a5a1c0b0d5adb2ed1a3bda5a21bf6c3e5372073d7a11cd4c5 # via -r requirements/dev.in +prompt-toolkit==3.0.47 \ + --hash=sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10 \ + --hash=sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360 + # via ipython +psutil==6.0.0 \ + --hash=sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35 \ + --hash=sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0 \ + --hash=sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c \ + --hash=sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1 \ + --hash=sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3 \ + --hash=sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c \ + --hash=sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd \ + --hash=sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3 \ + --hash=sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0 \ + --hash=sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2 \ + --hash=sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6 \ + --hash=sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d \ + --hash=sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c \ + --hash=sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0 \ + --hash=sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132 \ + --hash=sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14 \ + --hash=sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0 + # via ipykernel +ptyprocess==0.7.0 \ + --hash=sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35 \ + --hash=sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220 + # via pexpect +pure-eval==0.2.2 \ + --hash=sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350 \ + --hash=sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3 + # via stack-data +pybtex==0.24.0 \ + --hash=sha256:818eae35b61733e5c007c3fcd2cfb75ed1bc8b4173c1f70b56cc4c0802d34755 \ + --hash=sha256:e1e0c8c69998452fea90e9179aa2a98ab103f3eed894405b7264e517cc2fcc0f + # via + # pybtex-docutils + # sphinxcontrib-bibtex +pybtex-docutils==1.0.3 \ + --hash=sha256:3a7ebdf92b593e00e8c1c538aa9a20bca5d92d84231124715acc964d51d93c6b \ + --hash=sha256:8fd290d2ae48e32fcb54d86b0efb8d573198653c7e2447d5bec5847095f430b9 + # via sphinxcontrib-bibtex +pydantic==2.7.4 \ + --hash=sha256:0c84efd9548d545f63ac0060c1e4d39bb9b14db8b3c0652338aecc07b5adec52 \ + --hash=sha256:ee8538d41ccb9c0a9ad3e0e5f07bf15ed8015b481ced539a1759d8cc89ae90d0 + # via + # -c requirements/main.txt + # documenteer +pydantic-core==2.18.4 \ + --hash=sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3 \ + --hash=sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8 \ + --hash=sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8 \ + --hash=sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30 \ + --hash=sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a \ + --hash=sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8 \ + --hash=sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d \ + --hash=sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc \ + --hash=sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2 \ + --hash=sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab \ + --hash=sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077 \ + --hash=sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e \ + --hash=sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9 \ + --hash=sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9 \ + --hash=sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef \ + --hash=sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1 \ + --hash=sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507 \ + --hash=sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528 \ + --hash=sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558 \ + --hash=sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b \ + --hash=sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154 \ + --hash=sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724 \ + --hash=sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695 \ + --hash=sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9 \ + --hash=sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851 \ + --hash=sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805 \ + --hash=sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a \ + --hash=sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5 \ + --hash=sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94 \ + --hash=sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c \ + --hash=sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d \ + --hash=sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef \ + --hash=sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26 \ + --hash=sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2 \ + --hash=sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c \ + --hash=sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0 \ + --hash=sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2 \ + --hash=sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4 \ + --hash=sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d \ + --hash=sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2 \ + --hash=sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce \ + --hash=sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34 \ + --hash=sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f \ + --hash=sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d \ + --hash=sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b \ + --hash=sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07 \ + --hash=sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312 \ + --hash=sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057 \ + --hash=sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d \ + --hash=sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af \ + --hash=sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb \ + --hash=sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd \ + --hash=sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78 \ + --hash=sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b \ + --hash=sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223 \ + --hash=sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a \ + --hash=sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4 \ + --hash=sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5 \ + --hash=sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23 \ + --hash=sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a \ + --hash=sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4 \ + --hash=sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8 \ + --hash=sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d \ + --hash=sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443 \ + --hash=sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e \ + --hash=sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f \ + --hash=sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e \ + --hash=sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d \ + --hash=sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc \ + --hash=sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443 \ + --hash=sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be \ + --hash=sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2 \ + --hash=sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee \ + --hash=sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f \ + --hash=sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae \ + --hash=sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864 \ + --hash=sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4 \ + --hash=sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951 \ + --hash=sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc + # via + # -c requirements/main.txt + # pydantic +pydata-sphinx-theme==0.12.0 \ + --hash=sha256:7a07c3ac1fb1cfbb5f7d1e147a9500fb120e329d610e0fa2caac4a645141bdd9 \ + --hash=sha256:c17dbab67a3774f06f34f6378e896fcd0668cc8b5da1c1ba017e65cf1df0af58 + # via documenteer +pygments==2.18.0 \ + --hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \ + --hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a + # via + # -c requirements/main.txt + # ipython + # pydata-sphinx-theme + # sphinx + # sphinx-prompt +pylatexenc==2.10 \ + --hash=sha256:3dd8fd84eb46dc30bee1e23eaab8d8fb5a7f507347b23e5f38ad9675c84f40d3 + # via documenteer pytest==8.2.2 \ --hash=sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343 \ --hash=sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977 @@ -392,6 +807,10 @@ pytest-sugar==1.0.0 \ --hash=sha256:6422e83258f5b0c04ce7c632176c7732cab5fdb909cb39cca5c9139f81276c0a \ --hash=sha256:70ebcd8fc5795dc457ff8b69d266a4e2e8a74ae0c3edc749381c64b5246c8dfd # via -r requirements/dev.in +python-dateutil==2.9.0.post0 \ + --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ + --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 + # via jupyter-client pyyaml==6.0.1 \ --hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \ --hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \ @@ -446,17 +865,227 @@ pyyaml==6.0.1 \ --hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f # via # -c requirements/main.txt + # documenteer + # jupyter-cache + # myst-nb + # myst-parser # pre-commit + # pybtex + # sphinxcontrib-redoc +pyzmq==26.0.3 \ + --hash=sha256:01fbfbeb8249a68d257f601deb50c70c929dc2dfe683b754659569e502fbd3aa \ + --hash=sha256:0270b49b6847f0d106d64b5086e9ad5dc8a902413b5dbbb15d12b60f9c1747a4 \ + --hash=sha256:03c0ae165e700364b266876d712acb1ac02693acd920afa67da2ebb91a0b3c09 \ + --hash=sha256:068ca17214038ae986d68f4a7021f97e187ed278ab6dccb79f837d765a54d753 \ + --hash=sha256:082a2988364b60bb5de809373098361cf1dbb239623e39e46cb18bc035ed9c0c \ + --hash=sha256:0aaf982e68a7ac284377d051c742610220fd06d330dcd4c4dbb4cdd77c22a537 \ + --hash=sha256:0c0991f5a96a8e620f7691e61178cd8f457b49e17b7d9cfa2067e2a0a89fc1d5 \ + --hash=sha256:115f8359402fa527cf47708d6f8a0f8234f0e9ca0cab7c18c9c189c194dbf620 \ + --hash=sha256:15c59e780be8f30a60816a9adab900c12a58d79c1ac742b4a8df044ab2a6d920 \ + --hash=sha256:1b7d0e124948daa4d9686d421ef5087c0516bc6179fdcf8828b8444f8e461a77 \ + --hash=sha256:1c8eb19abe87029c18f226d42b8a2c9efdd139d08f8bf6e085dd9075446db450 \ + --hash=sha256:204e0f176fd1d067671157d049466869b3ae1fc51e354708b0dc41cf94e23a3a \ + --hash=sha256:2136f64fbb86451dbbf70223635a468272dd20075f988a102bf8a3f194a411dc \ + --hash=sha256:2b291d1230845871c00c8462c50565a9cd6026fe1228e77ca934470bb7d70ea0 \ + --hash=sha256:2c18645ef6294d99b256806e34653e86236eb266278c8ec8112622b61db255de \ + --hash=sha256:2cc4e280098c1b192c42a849de8de2c8e0f3a84086a76ec5b07bfee29bda7d18 \ + --hash=sha256:2ed8357f4c6e0daa4f3baf31832df8a33334e0fe5b020a61bc8b345a3db7a606 \ + --hash=sha256:3191d312c73e3cfd0f0afdf51df8405aafeb0bad71e7ed8f68b24b63c4f36500 \ + --hash=sha256:3401613148d93ef0fd9aabdbddb212de3db7a4475367f49f590c837355343972 \ + --hash=sha256:34106f68e20e6ff253c9f596ea50397dbd8699828d55e8fa18bd4323d8d966e6 \ + --hash=sha256:3516119f4f9b8671083a70b6afaa0a070f5683e431ab3dc26e9215620d7ca1ad \ + --hash=sha256:38ece17ec5f20d7d9b442e5174ae9f020365d01ba7c112205a4d59cf19dc38ee \ + --hash=sha256:3b4032a96410bdc760061b14ed6a33613ffb7f702181ba999df5d16fb96ba16a \ + --hash=sha256:3bf8b000a4e2967e6dfdd8656cd0757d18c7e5ce3d16339e550bd462f4857e59 \ + --hash=sha256:3e3070e680f79887d60feeda051a58d0ac36622e1759f305a41059eff62c6da7 \ + --hash=sha256:4496b1282c70c442809fc1b151977c3d967bfb33e4e17cedbf226d97de18f709 \ + --hash=sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625 \ + --hash=sha256:4adfbb5451196842a88fda3612e2c0414134874bffb1c2ce83ab4242ec9e027d \ + --hash=sha256:4b7c0c0b3244bb2275abe255d4a30c050d541c6cb18b870975553f1fb6f37527 \ + --hash=sha256:4c82a6d952a1d555bf4be42b6532927d2a5686dd3c3e280e5f63225ab47ac1f5 \ + --hash=sha256:5344b896e79800af86ad643408ca9aa303a017f6ebff8cee5a3163c1e9aec987 \ + --hash=sha256:5bde86a2ed3ce587fa2b207424ce15b9a83a9fa14422dcc1c5356a13aed3df9d \ + --hash=sha256:5bf6c237f8c681dfb91b17f8435b2735951f0d1fad10cc5dfd96db110243370b \ + --hash=sha256:5dbb9c997932473a27afa93954bb77a9f9b786b4ccf718d903f35da3232317de \ + --hash=sha256:69ea9d6d9baa25a4dc9cef5e2b77b8537827b122214f210dd925132e34ae9b12 \ + --hash=sha256:6b3146f9ae6af82c47a5282ac8803523d381b3b21caeae0327ed2f7ecb718798 \ + --hash=sha256:6bcb34f869d431799c3ee7d516554797f7760cb2198ecaa89c3f176f72d062be \ + --hash=sha256:6ca08b840fe95d1c2bd9ab92dac5685f949fc6f9ae820ec16193e5ddf603c3b2 \ + --hash=sha256:6ca7a9a06b52d0e38ccf6bca1aeff7be178917893f3883f37b75589d42c4ac20 \ + --hash=sha256:703c60b9910488d3d0954ca585c34f541e506a091a41930e663a098d3b794c67 \ + --hash=sha256:715bdf952b9533ba13dfcf1f431a8f49e63cecc31d91d007bc1deb914f47d0e4 \ + --hash=sha256:72b67f966b57dbd18dcc7efbc1c7fc9f5f983e572db1877081f075004614fcdd \ + --hash=sha256:74423631b6be371edfbf7eabb02ab995c2563fee60a80a30829176842e71722a \ + --hash=sha256:77a85dca4c2430ac04dc2a2185c2deb3858a34fe7f403d0a946fa56970cf60a1 \ + --hash=sha256:7821d44fe07335bea256b9f1f41474a642ca55fa671dfd9f00af8d68a920c2d4 \ + --hash=sha256:788f15721c64109cf720791714dc14afd0f449d63f3a5487724f024345067381 \ + --hash=sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd \ + --hash=sha256:7daa3e1369355766dea11f1d8ef829905c3b9da886ea3152788dc25ee6079e02 \ + --hash=sha256:7e6bc96ebe49604df3ec2c6389cc3876cabe475e6bfc84ced1bf4e630662cb35 \ + --hash=sha256:80b12f25d805a919d53efc0a5ad7c0c0326f13b4eae981a5d7b7cc343318ebb7 \ + --hash=sha256:871587bdadd1075b112e697173e946a07d722459d20716ceb3d1bd6c64bd08ce \ + --hash=sha256:88b88282e55fa39dd556d7fc04160bcf39dea015f78e0cecec8ff4f06c1fc2b5 \ + --hash=sha256:8d7a498671ca87e32b54cb47c82a92b40130a26c5197d392720a1bce1b3c77cf \ + --hash=sha256:926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf \ + --hash=sha256:971e8990c5cc4ddcff26e149398fc7b0f6a042306e82500f5e8db3b10ce69f84 \ + --hash=sha256:9b273ecfbc590a1b98f014ae41e5cf723932f3b53ba9367cfb676f838038b32c \ + --hash=sha256:a42db008d58530efa3b881eeee4991146de0b790e095f7ae43ba5cc612decbc5 \ + --hash=sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32 \ + --hash=sha256:ac97a21de3712afe6a6c071abfad40a6224fd14fa6ff0ff8d0c6e6cd4e2f807a \ + --hash=sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90 \ + --hash=sha256:b32bff85fb02a75ea0b68f21e2412255b5731f3f389ed9aecc13a6752f58ac97 \ + --hash=sha256:b3cd31f859b662ac5d7f4226ec7d8bd60384fa037fc02aee6ff0b53ba29a3ba8 \ + --hash=sha256:b63731993cdddcc8e087c64e9cf003f909262b359110070183d7f3025d1c56b5 \ + --hash=sha256:b6907da3017ef55139cf0e417c5123a84c7332520e73a6902ff1f79046cd3b94 \ + --hash=sha256:ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf \ + --hash=sha256:c1c8f2a2ca45292084c75bb6d3a25545cff0ed931ed228d3a1810ae3758f975f \ + --hash=sha256:ce828058d482ef860746bf532822842e0ff484e27f540ef5c813d516dd8896d2 \ + --hash=sha256:d0a2d1bd63a4ad79483049b26514e70fa618ce6115220da9efdff63688808b17 \ + --hash=sha256:d0cdde3c78d8ab5b46595054e5def32a755fc028685add5ddc7403e9f6de9879 \ + --hash=sha256:d57dfbf9737763b3a60d26e6800e02e04284926329aee8fb01049635e957fe81 \ + --hash=sha256:d8416c23161abd94cc7da80c734ad7c9f5dbebdadfdaa77dad78244457448223 \ + --hash=sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a \ + --hash=sha256:dbf012d8fcb9f2cf0643b65df3b355fdd74fc0035d70bb5c845e9e30a3a4654b \ + --hash=sha256:e1258c639e00bf5e8a522fec6c3eaa3e30cf1c23a2f21a586be7e04d50c9acab \ + --hash=sha256:e222562dc0f38571c8b1ffdae9d7adb866363134299264a1958d077800b193b7 \ + --hash=sha256:e4946d6bdb7ba972dfda282f9127e5756d4f299028b1566d1245fa0d438847e6 \ + --hash=sha256:e746524418b70f38550f2190eeee834db8850088c834d4c8406fbb9bc1ae10b2 \ + --hash=sha256:e76654e9dbfb835b3518f9938e565c7806976c07b37c33526b574cc1a1050480 \ + --hash=sha256:e8918973fbd34e7814f59143c5f600ecd38b8038161239fd1a3d33d5817a38b8 \ + --hash=sha256:e891ce81edd463b3b4c3b885c5603c00141151dd9c6936d98a680c8c72fe5c67 \ + --hash=sha256:ebbbd0e728af5db9b04e56389e2299a57ea8b9dd15c9759153ee2455b32be6ad \ + --hash=sha256:eeb438a26d87c123bb318e5f2b3d86a36060b01f22fbdffd8cf247d52f7c9a2b \ + --hash=sha256:eed56b6a39216d31ff8cd2f1d048b5bf1700e4b32a01b14379c3b6dde9ce3aa3 \ + --hash=sha256:f17cde1db0754c35a91ac00b22b25c11da6eec5746431d6e5092f0cd31a3fea9 \ + --hash=sha256:f1a9b7d00fdf60b4039f4455afd031fe85ee8305b019334b72dcf73c567edc47 \ + --hash=sha256:f4b6cecbbf3b7380f3b61de3a7b93cb721125dc125c854c14ddc91225ba52f83 \ + --hash=sha256:f6b1d1c631e5940cac5a0b22c5379c86e8df6a4ec277c7a856b714021ab6cfad \ + --hash=sha256:f6c21c00478a7bea93caaaef9e7629145d4153b15a8653e8bb4609d4bc70dbfc + # via + # ipykernel + # jupyter-client +referencing==0.35.1 \ + --hash=sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c \ + --hash=sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de + # via + # jsonschema + # jsonschema-specifications requests==2.32.3 \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 # via # -c requirements/main.txt + # documenteer # scriv + # sphinx + # sphinxcontrib-youtube respx==0.21.1 \ --hash=sha256:05f45de23f0c785862a2c92a3e173916e8ca88e4caad715dd5f68584d6053c20 \ --hash=sha256:0bd7fe21bfaa52106caa1223ce61224cf30786985f17c63c5d71eff0307ee8af # via -r requirements/dev.in +rpds-py==0.18.1 \ + --hash=sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee \ + --hash=sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc \ + --hash=sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc \ + --hash=sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944 \ + --hash=sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20 \ + --hash=sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7 \ + --hash=sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4 \ + --hash=sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6 \ + --hash=sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6 \ + --hash=sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93 \ + --hash=sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633 \ + --hash=sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0 \ + --hash=sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360 \ + --hash=sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8 \ + --hash=sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139 \ + --hash=sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7 \ + --hash=sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a \ + --hash=sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9 \ + --hash=sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26 \ + --hash=sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724 \ + --hash=sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72 \ + --hash=sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b \ + --hash=sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09 \ + --hash=sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100 \ + --hash=sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3 \ + --hash=sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261 \ + --hash=sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3 \ + --hash=sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9 \ + --hash=sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b \ + --hash=sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3 \ + --hash=sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de \ + --hash=sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d \ + --hash=sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e \ + --hash=sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8 \ + --hash=sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff \ + --hash=sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5 \ + --hash=sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c \ + --hash=sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e \ + --hash=sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e \ + --hash=sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4 \ + --hash=sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8 \ + --hash=sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922 \ + --hash=sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338 \ + --hash=sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d \ + --hash=sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8 \ + --hash=sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2 \ + --hash=sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72 \ + --hash=sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80 \ + --hash=sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644 \ + --hash=sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae \ + --hash=sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163 \ + --hash=sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104 \ + --hash=sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d \ + --hash=sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60 \ + --hash=sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a \ + --hash=sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d \ + --hash=sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07 \ + --hash=sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49 \ + --hash=sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10 \ + --hash=sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f \ + --hash=sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2 \ + --hash=sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8 \ + --hash=sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7 \ + --hash=sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88 \ + --hash=sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65 \ + --hash=sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0 \ + --hash=sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909 \ + --hash=sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8 \ + --hash=sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c \ + --hash=sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184 \ + --hash=sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397 \ + --hash=sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a \ + --hash=sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346 \ + --hash=sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590 \ + --hash=sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333 \ + --hash=sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb \ + --hash=sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74 \ + --hash=sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e \ + --hash=sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d \ + --hash=sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa \ + --hash=sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f \ + --hash=sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53 \ + --hash=sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1 \ + --hash=sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac \ + --hash=sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0 \ + --hash=sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd \ + --hash=sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611 \ + --hash=sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f \ + --hash=sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c \ + --hash=sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5 \ + --hash=sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab \ + --hash=sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc \ + --hash=sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43 \ + --hash=sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da \ + --hash=sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac \ + --hash=sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843 \ + --hash=sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e \ + --hash=sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89 \ + --hash=sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64 + # via + # jsonschema + # referencing ruff==0.4.10 \ --hash=sha256:0f54c481b39a762d48f64d97351048e842861c6662d63ec599f67d515cb417f6 \ --hash=sha256:18238c80ee3d9100d3535d8eb15a59c4a0753b45cc55f8bf38f38d6a597b9739 \ @@ -480,6 +1109,22 @@ scriv==1.5.1 \ --hash=sha256:30ae9ff8d144f8e0cf394c4e1d379542f1b3823767642955b54ec40dc00b32b6 \ --hash=sha256:a3adc657733b4124fcb54527a5f3daab0d3c300de82d0fd2b9b297b243151b78 # via -r requirements/dev.in +setuptools==70.1.1 \ + --hash=sha256:937a48c7cdb7a21eb53cd7f9b59e525503aa8abaf3584c730dc5f7a5bec3a650 \ + --hash=sha256:a58a8fde0541dab0419750bcc521fbdf8585f6e5cb41909df3a472ef7b81ca95 + # via documenteer +six==1.16.0 \ + --hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \ + --hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 + # via + # asttokens + # pybtex + # python-dateutil + # sphinxcontrib-redoc +smmap==5.0.1 \ + --hash=sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62 \ + --hash=sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da + # via gitdb sniffio==1.3.1 \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc @@ -488,10 +1133,203 @@ sniffio==1.3.1 \ # anyio # asgi-lifespan # httpx +snowballstemmer==2.2.0 \ + --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \ + --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a + # via sphinx +soupsieve==2.5 \ + --hash=sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690 \ + --hash=sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7 + # via beautifulsoup4 +sphinx==7.3.7 \ + --hash=sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3 \ + --hash=sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc + # via + # documenteer + # myst-nb + # myst-parser + # pydata-sphinx-theme + # sphinx-autodoc-typehints + # sphinx-automodapi + # sphinx-copybutton + # sphinx-design + # sphinx-jinja + # sphinx-prompt + # sphinxcontrib-bibtex + # sphinxcontrib-jquery + # sphinxcontrib-redoc + # sphinxcontrib-youtube + # sphinxext-opengraph + # sphinxext-rediraffe +sphinx-autodoc-typehints==2.2.2 \ + --hash=sha256:128e600eeef63b722f3d8dac6403594592c8cade3ba66fd11dcb997465ee259d \ + --hash=sha256:b98337a8530c95b73ba0c65465847a8ab0a13403bdc81294d5ef396bbd1f783e + # via documenteer +sphinx-automodapi==0.17.0 \ + --hash=sha256:4d029cb79eef29413e94ab01bb0177ebd2d5ba86e9789b73575afe9c06ae1501 \ + --hash=sha256:7ccdadad57add4aa9149d9f2bb5cf28c8f8b590280b4735b1156ea8355c423a1 + # via documenteer +sphinx-copybutton==0.5.2 \ + --hash=sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd \ + --hash=sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e + # via documenteer +sphinx-design==0.6.0 \ + --hash=sha256:e9bd07eecec82eb07ff72cb50fc3624e186b04f5661270bc7b62db86c7546e95 \ + --hash=sha256:ec8e3c5c59fed4049b3a5a2e209360feab31829346b5f6a0c7c342b894082192 + # 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 + # via documenteer +sphinxcontrib-applehelp==1.0.8 \ + --hash=sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619 \ + --hash=sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4 + # via sphinx +sphinxcontrib-bibtex==2.6.2 \ + --hash=sha256:10d45ebbb19207c5665396c9446f8012a79b8a538cb729f895b5910ab2d0b2da \ + --hash=sha256:f487af694336f28bfb7d6a17070953a7d264bec43000a2379724274f5f8d70ae + # via documenteer +sphinxcontrib-devhelp==1.0.6 \ + --hash=sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f \ + --hash=sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3 + # via sphinx +sphinxcontrib-htmlhelp==2.0.5 \ + --hash=sha256:0dc87637d5de53dd5eec3a6a01753b1ccf99494bd756aafecd74b4fa9e729015 \ + --hash=sha256:393f04f112b4d2f53d93448d4bce35842f62b307ccdc549ec1585e950bc35e04 + # via sphinx +sphinxcontrib-jquery==4.1 \ + --hash=sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a \ + --hash=sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae + # via documenteer +sphinxcontrib-jsmath==1.0.1 \ + --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \ + --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8 + # via sphinx +sphinxcontrib-mermaid==0.9.2 \ + --hash=sha256:252ef13dd23164b28f16d8b0205cf184b9d8e2b714a302274d9f59eb708e77af \ + --hash=sha256:6795a72037ca55e65663d2a2c1a043d636dc3d30d418e56dd6087d1459d98a5d + # via documenteer +sphinxcontrib-qthelp==1.0.7 \ + --hash=sha256:053dedc38823a80a7209a80860b16b722e9e0209e32fea98c90e4e6624588ed6 \ + --hash=sha256:e2ae3b5c492d58fcbd73281fbd27e34b8393ec34a073c792642cd8e529288182 + # via sphinx +sphinxcontrib-redoc==1.6.0 \ + --hash=sha256:e358edbe23927d36432dde748e978cf897283a331a03e93d3ef02e348dee4561 + # via documenteer +sphinxcontrib-serializinghtml==1.1.10 \ + --hash=sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7 \ + --hash=sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f + # 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 + # via documenteer +sphinxext-rediraffe==0.2.7 \ + --hash=sha256:651dcbfae5ffda9ffd534dfb8025f36120e5efb6ea1a33f5420023862b9f725d \ + --hash=sha256:9e430a52d4403847f4ffb3a8dd6dfc34a9fe43525305131f52ed899743a5fd8c + # via documenteer +sqlalchemy==2.0.31 \ + --hash=sha256:0b0f658414ee4e4b8cbcd4a9bb0fd743c5eeb81fc858ca517217a8013d282c96 \ + --hash=sha256:2196208432deebdfe3b22185d46b08f00ac9d7b01284e168c212919891289396 \ + --hash=sha256:23b9fbb2f5dd9e630db70fbe47d963c7779e9c81830869bd7d137c2dc1ad05fb \ + --hash=sha256:26a6a9837589c42b16693cf7bf836f5d42218f44d198f9343dd71d3164ceeeac \ + --hash=sha256:2a21c97efcbb9f255d5c12a96ae14da873233597dfd00a3a0c4ce5b3e5e79704 \ + --hash=sha256:2e2c38c2a4c5c634fe6c3c58a789712719fa1bf9b9d6ff5ebfce9a9e5b89c1ca \ + --hash=sha256:2fc47dc6185a83c8100b37acda27658fe4dbd33b7d5e7324111f6521008ab4fe \ + --hash=sha256:2fd17e3bb8058359fa61248c52c7b09a97cf3c820e54207a50af529876451808 \ + --hash=sha256:352b2770097f41bff6029b280c0e03b217c2dcaddc40726f8f53ed58d8a85da4 \ + --hash=sha256:3b74570d99126992d4b0f91fb87c586a574a5872651185de8297c6f90055ae42 \ + --hash=sha256:3cb8a66b167b033ec72c3812ffc8441d4e9f5f78f5e31e54dcd4c90a4ca5bebc \ + --hash=sha256:3f9faef422cfbb8fd53716cd14ba95e2ef655400235c3dfad1b5f467ba179c8c \ + --hash=sha256:4b600e9a212ed59355813becbcf282cfda5c93678e15c25a0ef896b354423238 \ + --hash=sha256:501ff052229cb79dd4c49c402f6cb03b5a40ae4771efc8bb2bfac9f6c3d3508f \ + --hash=sha256:56d51ae825d20d604583f82c9527d285e9e6d14f9a5516463d9705dab20c3740 \ + --hash=sha256:597fec37c382a5442ffd471f66ce12d07d91b281fd474289356b1a0041bdf31d \ + --hash=sha256:5a48ac4d359f058474fadc2115f78a5cdac9988d4f99eae44917f36aa1476327 \ + --hash=sha256:5b6cf796d9fcc9b37011d3f9936189b3c8074a02a4ed0c0fbbc126772c31a6d4 \ + --hash=sha256:66f63278db425838b3c2b1c596654b31939427016ba030e951b292e32b99553e \ + --hash=sha256:69f3e3c08867a8e4856e92d7afb618b95cdee18e0bc1647b77599722c9a28911 \ + --hash=sha256:6e2622844551945db81c26a02f27d94145b561f9d4b0c39ce7bfd2fda5776dac \ + --hash=sha256:6f77c4f042ad493cb8595e2f503c7a4fe44cd7bd59c7582fd6d78d7e7b8ec52c \ + --hash=sha256:74afabeeff415e35525bf7a4ecdab015f00e06456166a2eba7590e49f8db940e \ + --hash=sha256:750900a471d39a7eeba57580b11983030517a1f512c2cb287d5ad0fcf3aebd58 \ + --hash=sha256:78fe11dbe37d92667c2c6e74379f75746dc947ee505555a0197cfba9a6d4f1a4 \ + --hash=sha256:79a40771363c5e9f3a77f0e28b3302801db08040928146e6808b5b7a40749c88 \ + --hash=sha256:7bd112be780928c7f493c1a192cd8c5fc2a2a7b52b790bc5a84203fb4381c6be \ + --hash=sha256:8a41514c1a779e2aa9a19f67aaadeb5cbddf0b2b508843fcd7bafdf4c6864005 \ + --hash=sha256:9f2bee229715b6366f86a95d497c347c22ddffa2c7c96143b59a2aa5cc9eebbc \ + --hash=sha256:9fea3d0884e82d1e33226935dac990b967bef21315cbcc894605db3441347443 \ + --hash=sha256:afb6dde6c11ea4525318e279cd93c8734b795ac8bb5dda0eedd9ebaca7fa23f1 \ + --hash=sha256:b607489dd4a54de56984a0c7656247504bd5523d9d0ba799aef59d4add009484 \ + --hash=sha256:b6e22630e89f0e8c12332b2b4c282cb01cf4da0d26795b7eae16702a608e7ca1 \ + --hash=sha256:b9c01990d9015df2c6f818aa8f4297d42ee71c9502026bb074e713d496e26b67 \ + --hash=sha256:bd15026f77420eb2b324dcb93551ad9c5f22fab2c150c286ef1dc1160f110203 \ + --hash=sha256:c06fb43a51ccdff3b4006aafee9fcf15f63f23c580675f7734245ceb6b6a9e05 \ + --hash=sha256:c76c81c52e1e08f12f4b6a07af2b96b9b15ea67ccdd40ae17019f1c373faa227 \ + --hash=sha256:ccaf1b0c90435b6e430f5dd30a5aede4764942a695552eb3a4ab74ed63c5b8d3 \ + --hash=sha256:cd1591329333daf94467e699e11015d9c944f44c94d2091f4ac493ced0119449 \ + --hash=sha256:cd5b94d4819c0c89280b7c6109c7b788a576084bf0a480ae17c227b0bc41e109 \ + --hash=sha256:d337bf94052856d1b330d5fcad44582a30c532a2463776e1651bd3294ee7e58b \ + --hash=sha256:dc251477eae03c20fae8db9c1c23ea2ebc47331bcd73927cdcaecd02af98d3c3 \ + --hash=sha256:dc6d69f8829712a4fd799d2ac8d79bdeff651c2301b081fd5d3fe697bd5b4ab9 \ + --hash=sha256:f2a213c1b699d3f5768a7272de720387ae0122f1becf0901ed6eaa1abd1baf6c \ + --hash=sha256:f3ad7f221d8a69d32d197e5968d798217a4feebe30144986af71ada8c548e9fa \ + --hash=sha256:f43e93057cf52a227eda401251c72b6fbe4756f35fa6bfebb5d73b86881e59b0 \ + --hash=sha256:f68470edd70c3ac3b6cd5c2a22a8daf18415203ca1b036aaeb9b0fb6f54e8298 \ + --hash=sha256:fa4b1af3e619b5b0b435e333f3967612db06351217c58bfb50cee5f003db2a5a \ + --hash=sha256:fc6b14e8602f59c6ba893980bea96571dd0ed83d8ebb9c4479d9ed5425d562e9 + # 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 termcolor==2.4.0 \ --hash=sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63 \ --hash=sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a # via pytest-sugar +tomlkit==0.12.5 \ + --hash=sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f \ + --hash=sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c + # via documenteer +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.20240311 \ --hash=sha256:a9e0f0f88dc835739b0c1ca51ee90d04ca2a897a71af79de9aec5f38cb0a5342 \ --hash=sha256:b845b06a1c7e54b8e5b4c683043de0d9caf205e7434b3edc678ff2411979b8f6 @@ -506,14 +1344,31 @@ typing-extensions==4.12.2 \ # via # -c requirements/main.txt # mypy + # myst-nb + # pydantic + # pydantic-core + # sqlalchemy +uc-micro-py==1.0.3 \ + --hash=sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a \ + --hash=sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5 + # via linkify-it-py urllib3==2.2.2 \ --hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \ --hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168 # via # -c requirements/main.txt + # documenteer # requests # types-requests virtualenv==20.26.3 \ --hash=sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a \ --hash=sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589 # via pre-commit +wcwidth==0.2.13 \ + --hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 \ + --hash=sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5 + # via prompt-toolkit +zipp==3.19.2 \ + --hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \ + --hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c + # via importlib-metadata diff --git a/requirements/main.txt b/requirements/main.txt index 591d611e..878adc00 100644 --- a/requirements/main.txt +++ b/requirements/main.txt @@ -39,9 +39,9 @@ astropy==6.1.1 \ --hash=sha256:f6660b8a588c6de0e7796c68f9a1002fad934119af8c348cb9fb5456c3e2be53 \ --hash=sha256:ffa737cac938c0a97e6839cefb844fbe382c4c972fe0629a0628ec0bd9395b51 # via pyvo -astropy-iers-data==0.2024.6.17.0.31.35 \ - --hash=sha256:a6e0dca0985e15dfc4f3fc508bfb29b2b046b59eb9d028416860afa9c63b17eb \ - --hash=sha256:f4e0b40563813c4297745dd4ec03d80b2cbd6cb29340c8df0534b296cb27e3cf +astropy-iers-data==0.2024.6.24.0.31.11 \ + --hash=sha256:0b3799034b0b76af8f915ef822d38cc90e00e235db0cb688018e4f567a8babb9 \ + --hash=sha256:ef0197b7b84dea248031e553687ea1dc58d7ac9473043693b2d33b46d81a9a12 # via astropy certifi==2024.6.2 \ --hash=sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516 \ @@ -601,9 +601,9 @@ pydantic-core==2.18.4 \ --hash=sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951 \ --hash=sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc # via pydantic -pydantic-settings==2.3.3 \ - --hash=sha256:87fda838b64b5039b970cd47c3e8a1ee460ce136278ff672980af21516f6e6ce \ - --hash=sha256:e4ed62ad851670975ec11285141db888fd24947f9440bd4380d7d8788d4965de +pydantic-settings==2.3.4 \ + --hash=sha256:11ad8bacb68a045f00e4f862c7a718c8a9ec766aa8fd4c32e39a0594b207b53a \ + --hash=sha256:c5802e3d62b78e82522319bbc9b8f8ffb28ad1c988a99311d04f2a6051fca0a7 # via -r requirements/main.in pyerfa==2.0.1.4 \ --hash=sha256:39cf838c9a21e40d4e3183bead65b3ce6af763c4a727f87d84909c9be7d3a33c \ diff --git a/src/mobu/main.py b/src/mobu/main.py index 23522ed3..0a18f645 100644 --- a/src/mobu/main.py +++ b/src/mobu/main.py @@ -9,6 +9,7 @@ from __future__ import annotations +import json from collections.abc import AsyncIterator from contextlib import AsyncExitStack, asynccontextmanager from datetime import timedelta @@ -16,6 +17,7 @@ import structlog from fastapi import FastAPI +from fastapi.openapi.utils import get_openapi from safir.fastapi import ClientRequestError, client_request_error_handler from safir.logging import Profile, configure_logging, configure_uvicorn_logging from safir.middleware.x_forwarded import XForwardedMiddleware @@ -160,3 +162,15 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]: # Enable the generic exception handler for client errors. app.exception_handler(ClientRequestError)(client_request_error_handler) + + +def create_openapi() -> str: + """Create the OpenAPI spec for static documentation.""" + return json.dumps( + get_openapi( + title=app.title, + version=app.version, + description=app.description, + routes=app.routes, + ) + ) diff --git a/tox.ini b/tox.ini index 780921e0..a4a4e93c 100644 --- a/tox.ini +++ b/tox.ini @@ -18,6 +18,18 @@ depends = py commands = coverage report +[testenv:docs] +description = Build documentation (HTML) with Sphinx. +setenv = + MOBU_ENVIRONMENT_URL = https://test.example.com + MOBU_GITHUB_REFRESH_APP_ENABLED = true + MOBU_GITHUB_CI_APP_ENABLED = true +allowlist_externals = + rm +commands = + rm -rf docs/internals/api/ + sphinx-build -W --keep-going -n -T -b html -d {envtmpdir}/doctrees docs docs/_build/html + [testenv:typing] description = Run mypy. commands =