diff --git a/.github/workflows/api.yml b/.github/workflows/api.yml index a70add87..6b475fec 100644 --- a/.github/workflows/api.yml +++ b/.github/workflows/api.yml @@ -28,7 +28,7 @@ jobs: - name: Install dependencies run: | cd src/api - pipenv install -d . + pipenv install -d lint-api: needs: build-api @@ -53,6 +53,226 @@ jobs: - name: Lint with MyPy run: pipenv run mypy qualicharge tests + lint-bench: + needs: build-api + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./src/bench + steps: + - uses: actions/checkout@v4 + - name: Install pipenv + run: pipx install pipenv + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pipenv" + cache-dependency-path: "src/api/Pipfile.lock" + - name: Lint with Black + run: pipenv run black --check . + - name: Lint with Ruff + run: pipenv run ruff check . + - name: Lint with MyPy + run: pipenv run mypy . + + bench-api: + needs: build-api + runs-on: ubuntu-latest + services: + postgresql: + image: timescale/timescaledb-ha:pg14-ts2.14-oss + env: + POSTGRES_DB: qualicharge-api + POSTGRES_USER: qualicharge + POSTGRES_PASSWORD: pass + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + permissions: + pull-requests: write + contents: write + defaults: + run: + working-directory: ./src/api + env: + PORT: 8000 + QUALICHARGE_DB_ENGINE: postgresql+psycopg + QUALICHARGE_DB_HOST: localhost + QUALICHARGE_DB_NAME: qualicharge-api + QUALICHARGE_TEST_DB_NAME: test-qualicharge-api + QUALICHARGE_OIDC_IS_ENABLED: False + QUALICHARGE_ALLOWED_HOSTS: '["http://localhost:8000"]' + QUALICHARGE_API_STATIQUE_BULK_CREATE_MAX_SIZE: 1000 + QUALICHARGE_DEBUG: 0 + QUALICHARGE_PROFILING: 0 + QUALICHARGE_UVICORN_WORKERS: 1 + QUALICHARGE_DB_CONNECTION_MAX_OVERFLOW: 200 + QUALICHARGE_DB_CONNECTION_POOL_SIZE: 50 + QUALICHARGE_STATIQUE_DATA_PATH: /home/runner/work/qualicharge/qualicharge/data/irve-statique.json.gz + QUALICHARGE_API_ADMIN_USER: admin + QUALICHARGE_API_ADMIN_PASSWORD: admin + # This is a fake setting required to run the app + QUALICHARGE_OIDC_PROVIDER_BASE_URL: http://localhost:8000/fake + QUALICHARGE_OAUTH2_TOKEN_ENCODING_KEY: thisissupersecret + QUALICHARGE_OAUTH2_TOKEN_ISSUER: http://test:8000 + QUALICHARGE_EXECUTION_ENVIRONMENT: ci + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + - name: Create postgis extension + run: psql "postgresql://qualicharge:pass@localhost:5432/qualicharge-api" -c "create extension postgis;" + - name: Install pipenv + run: pipx install pipenv + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pipenv" + cache-dependency-path: "src/api/Pipfile.lock" + - name: Run database migrations + run: pipenv run alembic -c qualicharge/alembic.ini upgrade head + - name: Create API superuser + run: | + pipenv run python -m qualicharge create-user \ + admin \ + --email admin@example.com \ + --password admin \ + --is-active \ + --is-superuser \ + --is-staff \ + --force + - name: Seed API database + run: | + pipenv install -d --skip-lock qualicharge-client + pipenv run honcho start & + sleep 10 + zcat ../../data/irve-statique.json.gz | \ + head -n 500 | \ + pipenv run qcc static bulk --chunk-size 100 + env: + QCC_API_LOGIN_USERNAME: admin + QCC_API_LOGIN_PASSWORD: admin + QCC_API_ROOT_URL: "http://localhost:8000/api/v1" + # API server is still running here + - name: Run locust + run: | + pipenv run locust \ + -f ../bench/locustfile.py \ + --headless \ + -u 30 \ + -r 1 \ + --run-time 30s \ + -H "http://localhost:${PORT}/api/v1" \ + --csv bench_admin \ + --exit-code-on-error 0 \ + APIAdminUser + - name: Add bench file metadata + run: | + pipenv run \ + python ../bench/cli.py \ + stamp bench_admin_stats.csv $(git rev-parse --short "${GITHUB_SHA}") \ + > bench_admin_stats_stamped.csv + - name: Save bench CSV as artefact + uses: actions/upload-artifact@v4 + with: + name: api-admin-benchmark + path: ./src/api/bench_admin_stats_stamped.csv + - name: Generate markdown table + run: | + echo -e "### Current benchmark\n\n" >> bench_admin_stats.md && \ + pipenv run csvlook -I bench_admin_stats_stamped.csv >> bench_admin_stats.md && \ + echo -e "\n### Comparison with the latest previous benchmark\n\n" >> bench_admin_stats.md && \ + echo -e "> A lower (negative) value means the current version performs better than the previous one.\n\n" >> bench_admin_stats.md && \ + pipenv run \ + python ../bench/cli.py diff ../../data/bench.csv bench_admin_stats_stamped.csv | \ + pipenv run \ + csvlook -I >> bench_admin_stats.md + cat bench_admin_stats.md + - uses: actions/github-script@v7 + with: + script: | + const fs = require('node:fs'); + fs.readFile('/home/runner/work/qualicharge/qualicharge/src/api/bench_admin_stats.md', 'utf8', (err, data) => { + if (err) { + console.error(err); + return; + } + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: data + }); + }); + + # Only when a PR is merged + update-bench-db: + if: github.event.pull_request.merged == true + needs: + - build-api + - bench-api + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: write + defaults: + run: + working-directory: ./src/api + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + - name: Install pipenv + run: pipx install pipenv + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pipenv" + cache-dependency-path: "src/api/Pipfile.lock" + - name: Get latest bench CSV artefact + uses: actions/download-artifact@v4 + with: + name: api-admin-benchmark + path: ./src/api + - name: Merge Bench database + run: | + pipenv run \ + csvstack \ + ../../data/bench.csv \ + bench_admin_stats_stamped.csv \ + > /tmp/bench.csv + cp -f /tmp/bench.csv ../../data/bench.csv + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + add-paths: | + data/bench.csv + commit-message: | + ⚡️(api) update benchmark database + + Update bench database. + branch: update-api-bench-db + title: "⚡️(api) update benchmark database" + body: | + ## Purpose + + Each time a PR is merged and a new benchmark has been released, the bench database is updated. + + ## Proposal + + - [x] update `data/bench.csv` + + labels: | + API + needs review + test-database-migrations: needs: build-api runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index d5abbf9c..f4d0e860 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ scripts/*.csv # -- Tools .coverage +src/api/bench_*.csv # Prefect src/prefect/.htpasswd diff --git a/Makefile b/Makefile index 4bbac961..aa2d1a58 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,29 @@ data/afirev-charging.csv: data @echo "You should download CSV file from $(AFIREV_CHARGING_DATASET_URL)" # -- Docker/compose +bench-reset-db: ## Reset API database to run benchmark + $(COMPOSE) stop + $(COMPOSE) up -d --wait --force-recreate postgresql + $(MAKE) migrate-api + $(MAKE) create-api-superuser + $(COMPOSE) up -d --wait api + zcat data/irve-statique.json.gz | head -n 500 | \ + bin/qcc static bulk --chunk-size 1000 +.PHONY: bench-reset-db + +bench: ## run API benchmark + $(COMPOSE_RUN_API_PIPENV) \ + locust \ + -f /mnt/bench/locustfile.py \ + --headless \ + -u 30 \ + -r 1 \ + --run-time 30s \ + -H 'http://api:8000/api/v1' \ + --csv bench_admin \ + APIAdminUser +.PHONY: bench + bootstrap: ## bootstrap the project for development bootstrap: \ build \ @@ -61,6 +84,10 @@ build-client: ## build the client image $(COMPOSE) build client .PHONY: build-client +build-locust: ## build locust image + @$(COMPOSE) build locust +.PHONY: build-locust + build-notebook: ## build custom jupyter notebook image @$(COMPOSE) build notebook .PHONY: build-notebook @@ -134,6 +161,10 @@ run-dashboard: ## run the dashboard service $(COMPOSE_UP) dashboard .PHONY: run-dashboard +run-locust: ## run the locust service + $(COMPOSE_UP) --wait locust-worker +.PHONY: run-locust + status: ## an alias for "docker compose ps" @$(COMPOSE) ps .PHONY: status @@ -285,7 +316,6 @@ jupytext--to-ipynb: ## convert remote md files into ipynb reset-db: ## Reset the PostgreSQL database $(COMPOSE) stop - $(COMPOSE) down postgresql metabase $(MAKE) migrate-api $(MAKE) create-api-superuser $(MAKE) create-api-test-db @@ -339,6 +369,7 @@ seed-dashboard: ## seed dashboard lint: ## lint all sources lint: \ lint-api \ + lint-bench \ lint-client \ lint-prefect \ lint-dashboard @@ -351,6 +382,13 @@ lint-api: \ lint-api-mypy .PHONY: lint-api +lint-bench: ## lint api python sources +lint-bench: \ + lint-bench-black \ + lint-bench-ruff \ + lint-bench-mypy +.PHONY: lint-bench + lint-client: ## lint client python sources lint-client: \ lint-client-black \ @@ -393,6 +431,26 @@ lint-api-mypy: ## lint api python sources with mypy @$(COMPOSE_RUN_API_PIPENV) mypy qualicharge tests .PHONY: lint-api-mypy +lint-bench-black: ## lint bench python sources with black + @echo 'lint:black started…' + @$(COMPOSE_RUN_API_PIPENV) black /mnt/bench +.PHONY: lint-bench-black + +lint-bench-ruff: ## lint bench python sources with ruff + @echo 'lint:ruff started…' + @$(COMPOSE_RUN_API_PIPENV) ruff check /mnt/bench +.PHONY: lint-bench-ruff + +lint-bench-ruff-fix: ## lint and fix api python sources with ruff + @echo 'lint:ruff-fix started…' + @$(COMPOSE_RUN_API_PIPENV) ruff check --fix /mnt/bench +.PHONY: lint-bench-ruff-fix + +lint-bench-mypy: ## lint bench python sources with mypy + @echo 'lint:mypy started…' + @$(COMPOSE_RUN_API_PIPENV) mypy /mnt/bench +.PHONY: lint-bench-mypy + lint-client-black: ## lint api python sources with black @echo 'lint:black started…' @$(COMPOSE_RUN_CLIENT) black qcc tests diff --git a/data/bench.csv b/data/bench.csv new file mode 100644 index 00000000..173bdaf2 --- /dev/null +++ b/data/bench.csv @@ -0,0 +1,5 @@ +Type,Name,Request Count,Failure Count,Median Response Time,Average Response Time,Min Response Time,Max Response Time,Average Content Size,Requests/s,Failures/s,50%,66%,75%,80%,90%,95%,98%,99%,99.9%,99.99%,100%,git,timestamp,version +GET,/auth/whoami,449,0,41.0,190.682040076386,3.025668993359432,1548.9330790005624,160.0,15.502850350234926,0.0,41,250,290,320,530,760,920,1000,1500,1500,1500,e4bea93,2024-11-25 15:53:10.141468+00:00,0.15.0 +GET,/statique/?limit=10,415,0,190.0,309.7470774553037,15.45504099340178,1597.348899987992,13822.0,14.328915134404218,0.0,190,330,510,550,830,1000,1200,1400,1600,1600,1600,e4bea93,2024-11-25 15:53:10.141468+00:00,0.15.0 +GET,/statique/?limit=100,424,0,320.0,451.6924511111904,96.59699301118962,1808.202302985592,129002.0,14.639662691535875,0.0,320,510,590,720,1000,1100,1600,1700,1800,1800,1800,e4bea93,2024-11-25 15:53:10.141468+00:00,0.15.0 +,Aggregated,1288,0,220.0,314.9680686408331,3.025668993359432,1808.202302985592,46975.79037267081,44.47142817617502,0.0,230,320,500,540,810,1000,1200,1500,1800,1800,1800,e4bea93,2024-11-25 15:53:10.141468+00:00,0.15.0 diff --git a/docker-compose.yml b/docker-compose.yml index 022043de..bc5423a3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -43,8 +43,10 @@ services: volumes: - ./src/api:/app - ./data:/data + - ./src/bench:/mnt/bench depends_on: - - postgresql + postgresql: + condition: service_healthy client: build: @@ -75,7 +77,8 @@ services: volumes: - ./src/dashboard:/app depends_on: - - postgresql + postgresql: + condition: service_healthy keycloak: image: quay.io/keycloak/keycloak:26.0 @@ -104,7 +107,8 @@ services: timeout: 5s retries: 5 depends_on: - - postgresql + postgresql: + condition: service_healthy notebook: build: @@ -123,7 +127,8 @@ services: volumes: - .:/home/jovyan/work depends_on: - - postgresql + postgresql: + condition: service_healthy opendata: build: @@ -140,7 +145,8 @@ services: volumes: - ./src/opendata:/app depends_on: - - postgresql + postgresql: + condition: service_healthy prefect: build: @@ -167,7 +173,8 @@ services: volumes: - ./src/prefect:/app depends_on: - - postgresql + postgresql: + condition: service_healthy prefect-worker: image: "qualicharge:prefect" @@ -192,6 +199,45 @@ services: depends_on: - postgresql + locust: + build: + context: ./src/bench + args: + DOCKER_UID: ${DOCKER_UID:-1000} + DOCKER_GID: ${DOCKER_GID:-1000} + user: ${DOCKER_USER:-1000} + image: "qualicharge:locust" + ports: + - "8040:8089" + env_file: + - env.d/locust + volumes: + - ./src/bench:/app + - ./data:/data + command: -f /app/locustfile.py --master -H 'http://api:8000/api/v1' + depends_on: + api: + condition: service_healthy + + locust-worker: + build: + context: ./src/bench + args: + DOCKER_UID: ${DOCKER_UID:-1000} + DOCKER_GID: ${DOCKER_GID:-1000} + user: ${DOCKER_USER:-1000} + image: "qualicharge:locust" + deploy: + replicas: 5 + env_file: + - env.d/locust + volumes: + - ./src/bench:/app + - ./data:/data + command: -f /app/locustfile.py --worker --master-host locust + depends_on: + - locust + # -- tools curl: image: curlimages/curl:8.11.0 @@ -222,4 +268,3 @@ services: working_dir: /home/terraform volumes: - ./provisioning:/home/terraform - diff --git a/env.d/api b/env.d/api index 40d47514..b86fdff0 100644 --- a/env.d/api +++ b/env.d/api @@ -1,6 +1,10 @@ PORT=8000 QUALICHARGE_ALLOWED_HOSTS=["http://localhost:8010"] +QUALICHARGE_API_ADMIN_PASSWORD=admin +QUALICHARGE_API_ADMIN_USER=admin QUALICHARGE_API_STATIQUE_BULK_CREATE_MAX_SIZE=1000 +QUALICHARGE_DB_CONNECTION_MAX_OVERFLOW=200 +QUALICHARGE_DB_CONNECTION_POOL_SIZE=50 QUALICHARGE_DB_ENGINE=postgresql+psycopg QUALICHARGE_DB_HOST=postgresql QUALICHARGE_DB_NAME=qualicharge-api @@ -8,10 +12,12 @@ QUALICHARGE_DB_PASSWORD=pass QUALICHARGE_DB_PORT=5432 QUALICHARGE_DB_USER=qualicharge QUALICHARGE_DEBUG=1 -QUALICHARGE_PROFILING=1 QUALICHARGE_EXECUTION_ENVIRONMENT=development -QUALICHARGE_OIDC_PROVIDER_BASE_URL=http://keycloak:8080/realms/qualicharge -QUALICHARGE_OIDC_IS_ENABLED=False QUALICHARGE_OAUTH2_TOKEN_ENCODING_KEY=thisissupersecret QUALICHARGE_OAUTH2_TOKEN_ISSUER=http://localhost:8010 +QUALICHARGE_OIDC_IS_ENABLED=False +QUALICHARGE_OIDC_PROVIDER_BASE_URL=http://keycloak:8080/realms/qualicharge +QUALICHARGE_PROFILING=1 +QUALICHARGE_STATIQUE_DATA_PATH=/data/irve-statique.json.gz QUALICHARGE_TEST_DB_NAME=test-qualicharge-api +QUALICHARGE_UVICORN_WORKERS=1 diff --git a/env.d/bench b/env.d/bench new file mode 100644 index 00000000..e69de29b diff --git a/env.d/locust b/env.d/locust new file mode 100644 index 00000000..ec80abfd --- /dev/null +++ b/env.d/locust @@ -0,0 +1,3 @@ +QUALICHARGE_API_ADMIN_PASSWORD=admin +QUALICHARGE_API_ADMIN_USER=admin +QUALICHARGE_STATIQUE_DATA_PATH=/data/irve-statique.json.gz diff --git a/src/api/Dockerfile b/src/api/Dockerfile index 1a56d924..40c78b36 100644 --- a/src/api/Dockerfile +++ b/src/api/Dockerfile @@ -41,8 +41,7 @@ RUN mkdir /app && \ COPY --chown="${PIPENV_USER_NAME}:${PIPENV_GROUP_NAME}" . /app WORKDIR /app USER ${PIPENV_USER_NAME}:${PIPENV_GROUP_NAME} -RUN pipenv install -d && \ - pipenv install -e . +RUN pipenv install -d # -- Run -- CMD pipenv run honcho start diff --git a/src/api/Pipfile b/src/api/Pipfile index 1e2dca21..aa53b223 100644 --- a/src/api/Pipfile +++ b/src/api/Pipfile @@ -15,6 +15,7 @@ pandas = "==2.2.3" passlib = {extras = ["bcrypt"], version = "==1.7.4"} psycopg = {extras = ["pool", "binary"], version = "==3.2.3"} pyarrow = "==18.0.0" +pydantic = "==2.9.2" pydantic-extra-types = {extras = ["all"], version = "==2.10.0"} pydantic-settings = "==2.6.1" pyinstrument = "==5.0.0" @@ -32,15 +33,18 @@ uvicorn = {extras = ["standard"] } black = "==24.10.0" csvkit = "==2.0.1" honcho = "==2.0.0" +locust = "==2.32.2" mypy = "==1.13.0" pandas-stubs = "==2.2.3.241009" polyfactory = "==2.17.0" pytest = "==8.3.3" pytest-cov = "==6.0.0" pytest-httpx = "==0.34.0" +qualicharge = {path = ".", editable = true} ruff = "==0.7.4" types-passlib = "==1.7.7.20240819" types-python-jose = "==3.3.4.20240106" +types-requests = "==2.32.0.20241016" [requires] python_version = "3.12" diff --git a/src/api/Pipfile.lock b/src/api/Pipfile.lock index e35af987..7bc10fe3 100644 --- a/src/api/Pipfile.lock +++ b/src/api/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "6ae18042da690979f5612476ebef004f6f26483778ab84e915b18d7dc7bad217" + "sha256": "533530b88cc064e0282839c7e1ffeae1afe7f61e178ed61baed0ff98689bc014" }, "pipfile-spec": 6, "requires": { @@ -44,36 +44,34 @@ }, "bcrypt": { "hashes": [ - "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb", - "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399", - "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291", - "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d", - "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7", - "sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170", - "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d", - "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe", - "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060", - "sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184", - "sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a", - "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68", - "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c", - "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458", - "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9", - "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328", - "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7", - "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34", - "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e", - "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2", - "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5", - "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae", - "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00", - "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841", - "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8", - "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221", - "sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db" + "sha256:041fa0155c9004eb98a232d54da05c0b41d4b8e66b6fc3cb71b4b3f6144ba837", + "sha256:04e56e3fe8308a88b77e0afd20bec516f74aecf391cdd6e374f15cbed32783d6", + "sha256:1340411a0894b7d3ef562fb233e4b6ed58add185228650942bdc885362f32c17", + "sha256:533e7f3bcf2f07caee7ad98124fab7499cb3333ba2274f7a36cf1daee7409d99", + "sha256:6765386e3ab87f569b276988742039baab087b2cdb01e809d74e74503c2faafe", + "sha256:687cf30e6681eeda39548a93ce9bfbb300e48b4d445a43db4298d2474d2a1e54", + "sha256:76132c176a6d9953cdc83c296aeaed65e1a708485fd55abf163e0d9f8f16ce0e", + "sha256:76d3e352b32f4eeb34703370e370997065d28a561e4a18afe4fef07249cb4396", + "sha256:807261df60a8b1ccd13e6599c779014a362ae4e795f5c59747f60208daddd96d", + "sha256:89df2aea2c43be1e1fa066df5f86c8ce822ab70a30e4c210968669565c0f4685", + "sha256:8ad2f4528cbf0febe80e5a3a57d7a74e6635e41af1ea5675282a33d769fba413", + "sha256:8c458cd103e6c5d1d85cf600e546a639f234964d0228909d8f8dbeebff82d526", + "sha256:8dbd0747208912b1e4ce730c6725cb56c07ac734b3629b60d4398f082ea718ad", + "sha256:909faa1027900f2252a9ca5dfebd25fc0ef1417943824783d1c8418dd7d6df4a", + "sha256:aaa2e285be097050dba798d537b6efd9b698aa88eef52ec98d23dcd6d7cf6fea", + "sha256:adadd36274510a01f33e6dc08f5824b97c9580583bd4487c564fc4617b328005", + "sha256:b1ee315739bc8387aa36ff127afc99120ee452924e0df517a8f3e4c0187a0f5f", + "sha256:b588af02b89d9fad33e5f98f7838bf590d6d692df7153647724a7f20c186f6bf", + "sha256:b7703ede632dc945ed1172d6f24e9f30f27b1b1a067f32f68bf169c5f08d0425", + "sha256:c6f5fa3775966cca251848d4d5393ab016b3afed251163c1436fefdec3b02c84", + "sha256:cde78d385d5e93ece5479a0a87f73cd6fa26b171c786a884f955e165032b262c", + "sha256:cfdf3d7530c790432046c40cda41dfee8c83e29482e6a604f8930b9930e94139", + "sha256:e158009a54c4c8bc91d5e0da80920d048f918c61a581f0a63e4e93bb556d362f", + "sha256:e84e0e6f8e40a242b11bce56c313edc2be121cec3e0ec2d76fce01f6af33c07c", + "sha256:f85b1ffa09240c89aa2e1ae9f3b1c687104f7b2b9d2098da4e923f1b7082d331" ], "markers": "python_version >= '3.7'", - "version": "==4.2.0" + "version": "==4.2.1" }, "certifi": { "hashes": [ @@ -610,10 +608,10 @@ }, "phonenumbers": { "hashes": [ - "sha256:bb95dbc0d9979c51f7ad94bcd780784938958861fbb4b75a2fe39ccd3d58954a", - "sha256:e05ac6fb7b98c6d719a87ea895b9fc153673b4a51f455ec9afaf557ef4629da6" + "sha256:3bdacc0a155c8761c2a0ba7fc5632fe1541e5291ab70a4f345ab80a5742874b6", + "sha256:e8f4969841a163a3df3cb3ed8c499f0e00d58b2a1ecaa661e84e1d5fee67335f" ], - "version": "==8.13.50" + "version": "==8.13.51" }, "prompt-toolkit": { "hashes": [ @@ -775,6 +773,7 @@ "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12" ], + "index": "pypi", "markers": "python_version >= '3.8'", "version": "==2.9.2" }, @@ -1450,11 +1449,11 @@ "standard" ], "hashes": [ - "sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82", - "sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e" + "sha256:82ad92fd58da0d12af7482ecdb5f2470a04c9c9a53ced65b9bbb4a205377602e", + "sha256:ee9519c246a72b1c084cea8d3b44ed6026e78a4a309cbedae9c37e4cb9fbb175" ], "markers": "python_version >= '3.8'", - "version": "==0.32.0" + "version": "==0.32.1" }, "uvloop": { "hashes": [ @@ -1501,92 +1500,80 @@ }, "watchfiles": { "hashes": [ - "sha256:01550ccf1d0aed6ea375ef259706af76ad009ef5b0203a3a4cce0f6024f9b68a", - "sha256:01def80eb62bd5db99a798d5e1f5f940ca0a05986dcfae21d833af7a46f7ee22", - "sha256:07cdef0c84c03375f4e24642ef8d8178e533596b229d32d2bbd69e5128ede02a", - "sha256:083dc77dbdeef09fa44bb0f4d1df571d2e12d8a8f985dccde71ac3ac9ac067a0", - "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827", - "sha256:21ab23fdc1208086d99ad3f69c231ba265628014d4aed31d4e8746bd59e88cd1", - "sha256:2dadf8a8014fde6addfd3c379e6ed1a981c8f0a48292d662e27cabfe4239c83c", - "sha256:2e28d91ef48eab0afb939fa446d8ebe77e2f7593f5f463fd2bb2b14132f95b6e", - "sha256:2efec17819b0046dde35d13fb8ac7a3ad877af41ae4640f4109d9154ed30a188", - "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b", - "sha256:316449aefacf40147a9efaf3bd7c9bdd35aaba9ac5d708bd1eb5763c9a02bef5", - "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90", - "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef", - "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b", - "sha256:3770e260b18e7f4e576edca4c0a639f704088602e0bc921c5c2e721e3acb8d15", - "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48", - "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e", - "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df", - "sha256:449f43f49c8ddca87c6b3980c9284cab6bd1f5c9d9a2b00012adaaccd5e7decd", - "sha256:4933a508d2f78099162da473841c652ad0de892719043d3f07cc83b33dfd9d91", - "sha256:49d617df841a63b4445790a254013aea2120357ccacbed00253f9c2b5dc24e2d", - "sha256:49fb58bcaa343fedc6a9e91f90195b20ccb3135447dc9e4e2570c3a39565853e", - "sha256:4a7fa2bc0efef3e209a8199fd111b8969fe9db9c711acc46636686331eda7dd4", - "sha256:4abf4ad269856618f82dee296ac66b0cd1d71450fc3c98532d93798e73399b7a", - "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370", - "sha256:4d28cea3c976499475f5b7a2fec6b3a36208656963c1a856d328aeae056fc5c1", - "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea", - "sha256:54ca90a9ae6597ae6dc00e7ed0a040ef723f84ec517d3e7ce13e63e4bc82fa04", - "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896", - "sha256:5c51749f3e4e269231510da426ce4a44beb98db2dce9097225c338f815b05d4f", - "sha256:632676574429bee8c26be8af52af20e0c718cc7f5f67f3fb658c71928ccd4f7f", - "sha256:6509ed3f467b79d95fc62a98229f79b1a60d1b93f101e1c61d10c95a46a84f43", - "sha256:6bdcfa3cd6fdbdd1a068a52820f46a815401cbc2cb187dd006cb076675e7b735", - "sha256:7138eff8baa883aeaa074359daabb8b6c1e73ffe69d5accdc907d62e50b1c0da", - "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a", - "sha256:73bde715f940bea845a95247ea3e5eb17769ba1010efdc938ffcb967c634fa61", - "sha256:78470906a6be5199524641f538bd2c56bb809cd4bf29a566a75051610bc982c3", - "sha256:7ae3e208b31be8ce7f4c2c0034f33406dd24fbce3467f77223d10cd86778471c", - "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f", - "sha256:82ae557a8c037c42a6ef26c494d0631cacca040934b101d001100ed93d43f361", - "sha256:82b2509f08761f29a0fdad35f7e1638b8ab1adfa2666d41b794090361fb8b855", - "sha256:8360f7314a070c30e4c976b183d1d8d1585a4a50c5cb603f431cebcbb4f66327", - "sha256:85d5f0c7771dcc7a26c7a27145059b6bb0ce06e4e751ed76cdf123d7039b60b5", - "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab", - "sha256:9301c689051a4857d5b10777da23fafb8e8e921bcf3abe6448a058d27fb67633", - "sha256:951088d12d339690a92cef2ec5d3cfd957692834c72ffd570ea76a6790222777", - "sha256:95cf3b95ea665ab03f5a54765fa41abf0529dbaf372c3b83d91ad2cfa695779b", - "sha256:96619302d4374de5e2345b2b622dc481257a99431277662c30f606f3e22f42be", - "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f", - "sha256:9a60e2bf9dc6afe7f743e7c9b149d1fdd6dbf35153c78fe3a14ae1a9aee3d98b", - "sha256:9f895d785eb6164678ff4bb5cc60c5996b3ee6df3edb28dcdeba86a13ea0465e", - "sha256:a2a9891723a735d3e2540651184be6fd5b96880c08ffe1a98bae5017e65b544b", - "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366", - "sha256:aa0fd7248cf533c259e59dc593a60973a73e881162b1a2f73360547132742823", - "sha256:acbfa31e315a8f14fe33e3542cbcafc55703b8f5dcbb7c1eecd30f141df50db3", - "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1", - "sha256:b3ef2c69c655db63deb96b3c3e587084612f9b1fa983df5e0c3379d41307467f", - "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418", - "sha256:b665caeeda58625c3946ad7308fbd88a086ee51ccb706307e5b1fa91556ac886", - "sha256:b74fdffce9dfcf2dc296dec8743e5b0332d15df19ae464f0e249aa871fc1c571", - "sha256:b995bfa6bf01a9e09b884077a6d37070464b529d8682d7691c2d3b540d357a0c", - "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94", - "sha256:bdcd5538e27f188dd3c804b4a8d5f52a7fc7f87e7fd6b374b8e36a4ca03db428", - "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234", - "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6", - "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968", - "sha256:d337193bbf3e45171c8025e291530fb7548a93c45253897cd764a6a71c937ed9", - "sha256:d3dcb774e3568477275cc76554b5a565024b8ba3a0322f77c246bc7111c5bb9c", - "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e", - "sha256:d7a2e3b7f5703ffbd500dabdefcbc9eafeff4b9444bbdd5d83d79eedf8428fab", - "sha256:d831ee0a50946d24a53821819b2327d5751b0c938b12c0653ea5be7dea9c82ec", - "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444", - "sha256:e5171ef898299c657685306d8e1478a45e9303ddcd8ac5fed5bd52ad4ae0b69b", - "sha256:e94e98c7cb94cfa6e071d401ea3342767f28eb5a06a58fafdc0d2a4974f4f35c", - "sha256:ec39698c45b11d9694a1b635a70946a5bad066b593af863460a8e600f0dff1ca", - "sha256:ed9aba6e01ff6f2e8285e5aa4154e2970068fe0fc0998c4380d0e6278222269b", - "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18", - "sha256:ee82c98bed9d97cd2f53bdb035e619309a098ea53ce525833e26b93f673bc318", - "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07", - "sha256:f7d9b87c4c55e3ea8881dfcbf6d61ea6775fffed1fedffaa60bd047d3c08c430", - "sha256:f83df90191d67af5a831da3a33dd7628b02a95450e168785586ed51e6d28943c", - "sha256:fca9433a45f18b7c779d2bae7beeec4f740d28b788b117a48368d95a3233ed83", - "sha256:fd92bbaa2ecdb7864b7600dcdb6f2f1db6e0346ed425fbd01085be04c63f0b05" + "sha256:06d828fe2adc4ac8a64b875ca908b892a3603d596d43e18f7948f3fef5fc671c", + "sha256:074c7618cd6c807dc4eaa0982b4a9d3f8051cd0b72793511848fd64630174b17", + "sha256:09551237645d6bff3972592f2aa5424df9290e7a2e15d63c5f47c48cde585935", + "sha256:0fc3bf0effa2d8075b70badfdd7fb839d7aa9cea650d17886982840d71fdeabf", + "sha256:12ab123135b2f42517f04e720526d41448667ae8249e651385afb5cda31fedc0", + "sha256:13a4f9ee0cd25682679eea5c14fc629e2eaa79aab74d963bc4e21f43b8ea1877", + "sha256:1d19df28f99d6a81730658fbeb3ade8565ff687f95acb59665f11502b441be5f", + "sha256:1e176b6b4119b3f369b2b4e003d53a226295ee862c0962e3afd5a1c15680b4e3", + "sha256:1ee5edc939f53466b329bbf2e58333a5461e6c7b50c980fa6117439e2c18b42d", + "sha256:1f73c2147a453315d672c1ad907abe6d40324e34a185b51e15624bc793f93cc6", + "sha256:1ff236d7a3f4b0a42f699a22fc374ba526bc55048a70cbb299661158e1bb5e1f", + "sha256:245fab124b9faf58430da547512d91734858df13f2ddd48ecfa5e493455ffccb", + "sha256:28babb38cf2da8e170b706c4b84aa7e4528a6fa4f3ee55d7a0866456a1662041", + "sha256:28fb64b5843d94e2c2483f7b024a1280662a44409bedee8f2f51439767e2d107", + "sha256:29cf884ad4285d23453c702ed03d689f9c0e865e3c85d20846d800d4787de00f", + "sha256:2a825ba4b32c214e3855b536eb1a1f7b006511d8e64b8215aac06eb680642d84", + "sha256:2ac778a460ea22d63c7e6fb0bc0f5b16780ff0b128f7f06e57aaec63bd339285", + "sha256:2c2696611182c85eb0e755b62b456f48debff484b7306b56f05478b843ca8ece", + "sha256:2d9c0518fabf4a3f373b0a94bb9e4ea7a1df18dec45e26a4d182aa8918dee855", + "sha256:2de52b499e1ab037f1a87cb8ebcb04a819bf087b1015a4cf6dcf8af3c2a2613e", + "sha256:37566c844c9ce3b5deb964fe1a23378e575e74b114618d211fbda8f59d7b5dab", + "sha256:3d94fd83ed54266d789f287472269c0def9120a2022674990bd24ad989ebd7a0", + "sha256:48051d1c504448b2fcda71c5e6e3610ae45de6a0b8f5a43b961f250be4bdf5a8", + "sha256:487d15927f1b0bd24e7df921913399bb1ab94424c386bea8b267754d698f8f0e", + "sha256:4a3b33c3aefe9067ebd87846806cd5fc0b017ab70d628aaff077ab9abf4d06b3", + "sha256:4ff9c7e84e8b644a8f985c42bcc81457240316f900fc72769aaedec9d088055a", + "sha256:533a7cbfe700e09780bb31c06189e39c65f06c7f447326fee707fd02f9a6e945", + "sha256:53ae447f06f8f29f5ab40140f19abdab822387a7c426a369eb42184b021e97eb", + "sha256:550109001920a993a4383b57229c717fa73627d2a4e8fcb7ed33c7f1cddb0c85", + "sha256:5bbd0311588c2de7f9ea5cf3922ccacfd0ec0c1922870a2be503cc7df1ca8be7", + "sha256:5dccfc70480087567720e4e36ec381bba1ed68d7e5f368fe40c93b3b1eba0105", + "sha256:5f75cd42e7e2254117cf37ff0e68c5b3f36c14543756b2da621408349bd9ca7c", + "sha256:648e2b6db53eca6ef31245805cd528a16f56fa4cc15aeec97795eaf713c11435", + "sha256:774ef36b16b7198669ce655d4f75b4c3d370e7f1cbdfb997fb10ee98717e2058", + "sha256:8a2127cd68950787ee36753e6d401c8ea368f73beaeb8e54df5516a06d1ecd82", + "sha256:90004553be36427c3d06ec75b804233f8f816374165d5225b93abd94ba6e7234", + "sha256:905f69aad276639eff3893759a07d44ea99560e67a1cf46ff389cd62f88872a2", + "sha256:9122b8fdadc5b341315d255ab51d04893f417df4e6c1743b0aac8bf34e96e025", + "sha256:9272fdbc0e9870dac3b505bce1466d386b4d8d6d2bacf405e603108d50446940", + "sha256:936f362e7ff28311b16f0b97ec51e8f2cc451763a3264640c6ed40fb252d1ee4", + "sha256:947ccba18a38b85c366dafeac8df2f6176342d5992ca240a9d62588b214d731f", + "sha256:95dc785bc284552d044e561b8f4fe26d01ab5ca40d35852a6572d542adfeb4bc", + "sha256:95de85c254f7fe8cbdf104731f7f87f7f73ae229493bebca3722583160e6b152", + "sha256:9b4fb98100267e6a5ebaff6aaa5d20aea20240584647470be39fe4823012ac96", + "sha256:9c01446626574561756067f00b37e6b09c8622b0fc1e9fdbc7cbcea328d4e514", + "sha256:9c9a8d8fd97defe935ef8dd53d562e68942ad65067cd1c54d6ed8a088b1d931d", + "sha256:9e1d9284cc84de7855fcf83472e51d32daf6f6cecd094160192628bc3fee1b78", + "sha256:a0abf173975eb9dd17bb14c191ee79999e650997cc644562f91df06060610e62", + "sha256:a2218e78e2c6c07b1634a550095ac2a429026b2d5cbcd49a594f893f2bb8c936", + "sha256:a5a7a06cfc65e34fd0a765a7623c5ba14707a0870703888e51d3d67107589817", + "sha256:b2bca898c1dc073912d3db7fa6926cc08be9575add9e84872de2c99c688bac4e", + "sha256:b46e15c34d4e401e976d6949ad3a74d244600d5c4b88c827a3fdf18691a46359", + "sha256:b551c465a59596f3d08170bd7e1c532c7260dd90ed8135778038e13c5d48aa81", + "sha256:b555a93c15bd2c71081922be746291d776d47521a00703163e5fbe6d2a402399", + "sha256:bc338ce9f8846543d428260fa0f9a716626963148edc937d71055d01d81e1525", + "sha256:bedf84835069f51c7b026b3ca04e2e747ea8ed0a77c72006172c72d28c9f69fc", + "sha256:c3d258d78341d5d54c0c804a5b7faa66cd30ba50b2756a7161db07ce15363b8d", + "sha256:c83a6d33a9eda0af6a7470240d1af487807adc269704fe76a4972dd982d16236", + "sha256:c9a13ac46b545a7d0d50f7641eefe47d1597e7d1783a5d89e09d080e6dff44b0", + "sha256:cf517701a4a872417f4e02a136e929537743461f9ec6cdb8184d9a04f4843545", + "sha256:d2b39aa8edd9e5f56f99a2a2740a251dc58515398e9ed5a4b3e5ff2827060755", + "sha256:d3572d4c34c4e9c33d25b3da47d9570d5122f8433b9ac6519dca49c2740d23cd", + "sha256:d562a6114ddafb09c33246c6ace7effa71ca4b6a2324a47f4b09b6445ea78941", + "sha256:e1ed613ee107269f66c2df631ec0fc8efddacface85314d392a4131abe299f00", + "sha256:e3750434c83b61abb3163b49c64b04180b85b4dabb29a294513faec57f2ffdb7", + "sha256:eba98901a2eab909dbd79681190b9049acc650f6111fde1845484a4450761e98", + "sha256:f159ac795785cde4899e0afa539f4c723fb5dd336ce5605bc909d34edd00b79b", + "sha256:f8c4f3a1210ed099a99e6a710df4ff2f8069411059ffe30fa5f9467ebed1256b", + "sha256:fa13d604fcb9417ae5f2e3de676e66aa97427d888e83662ad205bed35a313176", + "sha256:fbd0ab7a9943bbddb87cbc2bf2f09317e74c77dc55b1f5657f81d04666c25269", + "sha256:ffd98a299b0a74d1b704ef0ed959efb753e656a4e0425c14e46ae4c3cbdd2919" ], - "markers": "python_version >= '3.8'", - "version": "==0.24.0" + "markers": "python_version >= '3.9'", + "version": "==1.0.0" }, "wcwidth": { "hashes": [ @@ -1745,6 +1732,144 @@ "markers": "python_version >= '3.9'", "version": "==24.10.0" }, + "blinker": { + "hashes": [ + "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", + "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc" + ], + "markers": "python_version >= '3.9'", + "version": "==1.9.0" + }, + "brotli": { + "hashes": [ + "sha256:03d20af184290887bdea3f0f78c4f737d126c74dc2f3ccadf07e54ceca3bf208", + "sha256:0541e747cce78e24ea12d69176f6a7ddb690e62c425e01d31cc065e69ce55b48", + "sha256:069a121ac97412d1fe506da790b3e69f52254b9df4eb665cd42460c837193354", + "sha256:0737ddb3068957cf1b054899b0883830bb1fec522ec76b1098f9b6e0f02d9419", + "sha256:0b63b949ff929fbc2d6d3ce0e924c9b93c9785d877a21a1b678877ffbbc4423a", + "sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128", + "sha256:11d00ed0a83fa22d29bc6b64ef636c4552ebafcef57154b4ddd132f5638fbd1c", + "sha256:141bd4d93984070e097521ed07e2575b46f817d08f9fa42b16b9b5f27b5ac088", + "sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9", + "sha256:1ab4fbee0b2d9098c74f3057b2bc055a8bd92ccf02f65944a241b4349229185a", + "sha256:1ae56aca0402a0f9a3431cddda62ad71666ca9d4dc3a10a142b9dce2e3c0cda3", + "sha256:1b2c248cd517c222d89e74669a4adfa5577e06ab68771a529060cf5a156e9757", + "sha256:1e9a65b5736232e7a7f91ff3d02277f11d339bf34099a56cdab6a8b3410a02b2", + "sha256:224e57f6eac61cc449f498cc5f0e1725ba2071a3d4f48d5d9dffba42db196438", + "sha256:22fc2a8549ffe699bfba2256ab2ed0421a7b8fadff114a3d201794e45a9ff578", + "sha256:23032ae55523cc7bccb4f6a0bf368cd25ad9bcdcc1990b64a647e7bbcce9cb5b", + "sha256:2333e30a5e00fe0fe55903c8832e08ee9c3b1382aacf4db26664a16528d51b4b", + "sha256:2954c1c23f81c2eaf0b0717d9380bd348578a94161a65b3a2afc62c86467dd68", + "sha256:2a24c50840d89ded6c9a8fdc7b6ed3692ed4e86f1c4a4a938e1e92def92933e0", + "sha256:2de9d02f5bda03d27ede52e8cfe7b865b066fa49258cbab568720aa5be80a47d", + "sha256:2feb1d960f760a575dbc5ab3b1c00504b24caaf6986e2dc2b01c09c87866a943", + "sha256:30924eb4c57903d5a7526b08ef4a584acc22ab1ffa085faceb521521d2de32dd", + "sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409", + "sha256:32d95b80260d79926f5fab3c41701dbb818fde1c9da590e77e571eefd14abe28", + "sha256:38025d9f30cf4634f8309c6874ef871b841eb3c347e90b0851f63d1ded5212da", + "sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50", + "sha256:3c0ef38c7a7014ffac184db9e04debe495d317cc9c6fb10071f7fefd93100a4f", + "sha256:3d7954194c36e304e1523f55d7042c59dc53ec20dd4e9ea9d151f1b62b4415c0", + "sha256:3ee8a80d67a4334482d9712b8e83ca6b1d9bc7e351931252ebef5d8f7335a547", + "sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180", + "sha256:43395e90523f9c23a3d5bdf004733246fba087f2948f87ab28015f12359ca6a0", + "sha256:43ce1b9935bfa1ede40028054d7f48b5469cd02733a365eec8a329ffd342915d", + "sha256:4410f84b33374409552ac9b6903507cdb31cd30d2501fc5ca13d18f73548444a", + "sha256:494994f807ba0b92092a163a0a283961369a65f6cbe01e8891132b7a320e61eb", + "sha256:4d4a848d1837973bf0f4b5e54e3bec977d99be36a7895c61abb659301b02c112", + "sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc", + "sha256:4f3607b129417e111e30637af1b56f24f7a49e64763253bbc275c75fa887d4b2", + "sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265", + "sha256:524f35912131cc2cabb00edfd8d573b07f2d9f21fa824bd3fb19725a9cf06327", + "sha256:587ca6d3cef6e4e868102672d3bd9dc9698c309ba56d41c2b9c85bbb903cdb95", + "sha256:58d4b711689366d4a03ac7957ab8c28890415e267f9b6589969e74b6e42225ec", + "sha256:5b3cc074004d968722f51e550b41a27be656ec48f8afaeeb45ebf65b561481dd", + "sha256:5dab0844f2cf82be357a0eb11a9087f70c5430b2c241493fc122bb6f2bb0917c", + "sha256:5e55da2c8724191e5b557f8e18943b1b4839b8efc3ef60d65985bcf6f587dd38", + "sha256:5eeb539606f18a0b232d4ba45adccde4125592f3f636a6182b4a8a436548b914", + "sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0", + "sha256:5fb2ce4b8045c78ebbc7b8f3c15062e435d47e7393cc57c25115cfd49883747a", + "sha256:6172447e1b368dcbc458925e5ddaf9113477b0ed542df258d84fa28fc45ceea7", + "sha256:6967ced6730aed543b8673008b5a391c3b1076d834ca438bbd70635c73775368", + "sha256:6974f52a02321b36847cd19d1b8e381bf39939c21efd6ee2fc13a28b0d99348c", + "sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0", + "sha256:6c6e0c425f22c1c719c42670d561ad682f7bfeeef918edea971a79ac5252437f", + "sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451", + "sha256:7905193081db9bfa73b1219140b3d315831cbff0d8941f22da695832f0dd188f", + "sha256:7bc37c4d6b87fb1017ea28c9508b36bbcb0c3d18b4260fcdf08b200c74a6aee8", + "sha256:7c4855522edb2e6ae7fdb58e07c3ba9111e7621a8956f481c68d5d979c93032e", + "sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248", + "sha256:7eedaa5d036d9336c95915035fb57422054014ebdeb6f3b42eac809928e40d0c", + "sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91", + "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724", + "sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7", + "sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966", + "sha256:87a3044c3a35055527ac75e419dfa9f4f3667a1e887ee80360589eb8c90aabb9", + "sha256:890b5a14ce214389b2cc36ce82f3093f96f4cc730c1cffdbefff77a7c71f2a97", + "sha256:89f4988c7203739d48c6f806f1e87a1d96e0806d44f0fba61dba81392c9e474d", + "sha256:8bf32b98b75c13ec7cf774164172683d6e7891088f6316e54425fde1efc276d5", + "sha256:8dadd1314583ec0bf2d1379f7008ad627cd6336625d6679cf2f8e67081b83acf", + "sha256:901032ff242d479a0efa956d853d16875d42157f98951c0230f69e69f9c09bac", + "sha256:9011560a466d2eb3f5a6e4929cf4a09be405c64154e12df0dd72713f6500e32b", + "sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951", + "sha256:919e32f147ae93a09fe064d77d5ebf4e35502a8df75c29fb05788528e330fe74", + "sha256:91d7cc2a76b5567591d12c01f019dd7afce6ba8cba6571187e21e2fc418ae648", + "sha256:929811df5462e182b13920da56c6e0284af407d1de637d8e536c5cd00a7daf60", + "sha256:949f3b7c29912693cee0afcf09acd6ebc04c57af949d9bf77d6101ebb61e388c", + "sha256:a090ca607cbb6a34b0391776f0cb48062081f5f60ddcce5d11838e67a01928d1", + "sha256:a1fd8a29719ccce974d523580987b7f8229aeace506952fa9ce1d53a033873c8", + "sha256:a37b8f0391212d29b3a91a799c8e4a2855e0576911cdfb2515487e30e322253d", + "sha256:a3daabb76a78f829cafc365531c972016e4aa8d5b4bf60660ad8ecee19df7ccc", + "sha256:a469274ad18dc0e4d316eefa616d1d0c2ff9da369af19fa6f3daa4f09671fd61", + "sha256:a599669fd7c47233438a56936988a2478685e74854088ef5293802123b5b2460", + "sha256:a743e5a28af5f70f9c080380a5f908d4d21d40e8f0e0c8901604d15cfa9ba751", + "sha256:a77def80806c421b4b0af06f45d65a136e7ac0bdca3c09d9e2ea4e515367c7e9", + "sha256:a7e53012d2853a07a4a79c00643832161a910674a893d296c9f1259859a289d2", + "sha256:a93dde851926f4f2678e704fadeb39e16c35d8baebd5252c9fd94ce8ce68c4a0", + "sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1", + "sha256:ae15b066e5ad21366600ebec29a7ccbc86812ed267e4b28e860b8ca16a2bc474", + "sha256:aea440a510e14e818e67bfc4027880e2fb500c2ccb20ab21c7a7c8b5b4703d75", + "sha256:af6fa6817889314555aede9a919612b23739395ce767fe7fcbea9a80bf140fe5", + "sha256:b760c65308ff1e462f65d69c12e4ae085cff3b332d894637f6273a12a482d09f", + "sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2", + "sha256:c247dd99d39e0338a604f8c2b3bc7061d5c2e9e2ac7ba9cc1be5a69cb6cd832f", + "sha256:c5529b34c1c9d937168297f2c1fde7ebe9ebdd5e121297ff9c043bdb2ae3d6fb", + "sha256:c8146669223164fc87a7e3de9f81e9423c67a79d6b3447994dfb9c95da16e2d6", + "sha256:c8fd5270e906eef71d4a8d19b7c6a43760c6abcfcc10c9101d14eb2357418de9", + "sha256:ca63e1890ede90b2e4454f9a65135a4d387a4585ff8282bb72964fab893f2111", + "sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2", + "sha256:cb1dac1770878ade83f2ccdf7d25e494f05c9165f5246b46a621cc849341dc01", + "sha256:cdad5b9014d83ca68c25d2e9444e28e967ef16e80f6b436918c700c117a85467", + "sha256:cdbc1fc1bc0bff1cef838eafe581b55bfbffaed4ed0318b724d0b71d4d377619", + "sha256:ceb64bbc6eac5a140ca649003756940f8d6a7c444a68af170b3187623b43bebf", + "sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408", + "sha256:d143fd47fad1db3d7c27a1b1d66162e855b5d50a89666af46e1679c496e8e579", + "sha256:d192f0f30804e55db0d0e0a35d83a9fead0e9a359a9ed0285dbacea60cc10a84", + "sha256:d2b35ca2c7f81d173d2fadc2f4f31e88cc5f7a39ae5b6db5513cf3383b0e0ec7", + "sha256:d342778ef319e1026af243ed0a07c97acf3bad33b9f29e7ae6a1f68fd083e90c", + "sha256:d487f5432bf35b60ed625d7e1b448e2dc855422e87469e3f450aa5552b0eb284", + "sha256:d7702622a8b40c49bffb46e1e3ba2e81268d5c04a34f460978c6b5517a34dd52", + "sha256:db85ecf4e609a48f4b29055f1e144231b90edc90af7481aa731ba2d059226b1b", + "sha256:de6551e370ef19f8de1807d0a9aa2cdfdce2e85ce88b122fe9f6b2b076837e59", + "sha256:e1140c64812cb9b06c922e77f1c26a75ec5e3f0fb2bf92cc8c58720dec276752", + "sha256:e4fe605b917c70283db7dfe5ada75e04561479075761a0b3866c081d035b01c1", + "sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80", + "sha256:e79e6520141d792237c70bcd7a3b122d00f2613769ae0cb61c52e89fd3443839", + "sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0", + "sha256:e93dfc1a1165e385cc8239fab7c036fb2cd8093728cbd85097b284d7b99249a2", + "sha256:efa8b278894b14d6da122a72fefcebc28445f2d3f880ac59d46c90f4c13be9a3", + "sha256:f0d8a7a6b5983c2496e364b969f0e526647a06b075d034f3297dc66f3b360c64", + "sha256:f0db75f47be8b8abc8d9e31bc7aad0547ca26f24a54e6fd10231d623f183d089", + "sha256:f296c40e23065d0d6650c4aefe7470d2a25fffda489bcc3eb66083f3ac9f6643", + "sha256:f31859074d57b4639318523d6ffdca586ace54271a73ad23ad021acd807eb14b", + "sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e", + "sha256:f733d788519c7e3e71f0855c96618720f5d3d60c3cb829d8bbb722dddce37985", + "sha256:fce1473f3ccc4187f75b4690cfc922628aed4d3dd013d047f95a9b3919a86596", + "sha256:fd5f17ff8f14003595ab414e45fce13d073e0762394f957182e69035c9f3d7c2", + "sha256:fdc3ff3bfccdc6b9cc7c342c03aa2400683f0cb891d46e94b64a197910dc4064" + ], + "version": "==1.1.0" + }, "certifi": { "hashes": [ "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", @@ -1753,6 +1878,117 @@ "markers": "python_version >= '3.6'", "version": "==2024.8.30" }, + "charset-normalizer": { + "hashes": [ + "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621", + "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", + "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", + "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912", + "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", + "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b", + "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d", + "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d", + "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95", + "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e", + "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", + "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", + "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab", + "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be", + "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", + "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907", + "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0", + "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2", + "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62", + "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62", + "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", + "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", + "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", + "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca", + "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455", + "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858", + "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", + "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", + "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", + "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", + "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", + "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea", + "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6", + "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", + "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749", + "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", + "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd", + "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99", + "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242", + "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee", + "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", + "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", + "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51", + "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", + "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8", + "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", + "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613", + "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742", + "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe", + "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3", + "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", + "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", + "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7", + "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", + "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", + "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", + "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417", + "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", + "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", + "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca", + "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa", + "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", + "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149", + "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41", + "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574", + "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0", + "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f", + "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", + "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654", + "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3", + "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19", + "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", + "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578", + "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", + "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", + "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51", + "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", + "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", + "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a", + "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", + "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade", + "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", + "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc", + "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6", + "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", + "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", + "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6", + "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2", + "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12", + "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf", + "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", + "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7", + "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", + "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", + "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b", + "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", + "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", + "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4", + "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", + "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", + "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a", + "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748", + "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b", + "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", + "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.4.0" + }, "click": { "hashes": [ "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", @@ -1761,76 +1997,84 @@ "markers": "python_version >= '3.7'", "version": "==8.1.7" }, + "configargparse": { + "hashes": [ + "sha256:d249da6591465c6c26df64a9f73d2536e743be2f244eb3ebe61114af2f94f86b", + "sha256:e7067471884de5478c58a511e529f0f9bd1c66bfef1dea90935438d6c23306d1" + ], + "markers": "python_version >= '3.5'", + "version": "==1.7" + }, "coverage": { "extras": [ "toml" ], "hashes": [ - "sha256:0266b62cbea568bd5e93a4da364d05de422110cbed5056d69339bd5af5685433", - "sha256:0573f5cbf39114270842d01872952d301027d2d6e2d84013f30966313cadb529", - "sha256:0ddcb70b3a3a57581b450571b31cb774f23eb9519c2aaa6176d3a84c9fc57671", - "sha256:108bb458827765d538abcbf8288599fee07d2743357bdd9b9dad456c287e121e", - "sha256:14045b8bfd5909196a90da145a37f9d335a5d988a83db34e80f41e965fb7cb42", - "sha256:1a5407a75ca4abc20d6252efeb238377a71ce7bda849c26c7a9bece8680a5d99", - "sha256:2bc3e45c16564cc72de09e37413262b9f99167803e5e48c6156bccdfb22c8327", - "sha256:2d608a7808793e3615e54e9267519351c3ae204a6d85764d8337bd95993581a8", - "sha256:34d23e28ccb26236718a3a78ba72744212aa383141961dd6825f6595005c8b06", - "sha256:37a15573f988b67f7348916077c6d8ad43adb75e478d0910957394df397d2874", - "sha256:3c0317288f032221d35fa4cbc35d9f4923ff0dfd176c79c9b356e8ef8ef2dff4", - "sha256:3c42ec2c522e3ddd683dec5cdce8e62817afb648caedad9da725001fa530d354", - "sha256:3c6b24007c4bcd0b19fac25763a7cac5035c735ae017e9a349b927cfc88f31c1", - "sha256:40cca284c7c310d622a1677f105e8507441d1bb7c226f41978ba7c86979609ab", - "sha256:46f21663e358beae6b368429ffadf14ed0a329996248a847a4322fb2e35d64d3", - "sha256:49ed5ee4109258973630c1f9d099c7e72c5c36605029f3a91fe9982c6076c82b", - "sha256:5c95e0fa3d1547cb6f021ab72f5c23402da2358beec0a8e6d19a368bd7b0fb37", - "sha256:5dd4e4a49d9c72a38d18d641135d2fb0bdf7b726ca60a103836b3d00a1182acd", - "sha256:5e444b8e88339a2a67ce07d41faabb1d60d1004820cee5a2c2b54e2d8e429a0f", - "sha256:60dcf7605c50ea72a14490d0756daffef77a5be15ed1b9fea468b1c7bda1bc3b", - "sha256:623e6965dcf4e28a3debaa6fcf4b99ee06d27218f46d43befe4db1c70841551c", - "sha256:673184b3156cba06154825f25af33baa2671ddae6343f23175764e65a8c4c30b", - "sha256:6cf96ceaa275f071f1bea3067f8fd43bec184a25a962c754024c973af871e1b7", - "sha256:70a56a2ec1869e6e9fa69ef6b76b1a8a7ef709972b9cc473f9ce9d26b5997ce3", - "sha256:77256ad2345c29fe59ae861aa11cfc74579c88d4e8dbf121cbe46b8e32aec808", - "sha256:796c9b107d11d2d69e1849b2dfe41730134b526a49d3acb98ca02f4985eeff7a", - "sha256:7c07de0d2a110f02af30883cd7dddbe704887617d5c27cf373362667445a4c76", - "sha256:7e61b0e77ff4dddebb35a0e8bb5a68bf0f8b872407d8d9f0c726b65dfabe2469", - "sha256:82c809a62e953867cf57e0548c2b8464207f5f3a6ff0e1e961683e79b89f2c55", - "sha256:850cfd2d6fc26f8346f422920ac204e1d28814e32e3a58c19c91980fa74d8289", - "sha256:87ea64b9fa52bf395272e54020537990a28078478167ade6c61da7ac04dc14bc", - "sha256:90746521206c88bdb305a4bf3342b1b7316ab80f804d40c536fc7d329301ee13", - "sha256:951aade8297358f3618a6e0660dc74f6b52233c42089d28525749fc8267dccd2", - "sha256:963e4a08cbb0af6623e61492c0ec4c0ec5c5cf74db5f6564f98248d27ee57d30", - "sha256:987a8e3da7da4eed10a20491cf790589a8e5e07656b6dc22d3814c4d88faf163", - "sha256:9c2eb378bebb2c8f65befcb5147877fc1c9fbc640fc0aad3add759b5df79d55d", - "sha256:a1ab9763d291a17b527ac6fd11d1a9a9c358280adb320e9c2672a97af346ac2c", - "sha256:a3b925300484a3294d1c70f6b2b810d6526f2929de954e5b6be2bf8caa1f12c1", - "sha256:acbb8af78f8f91b3b51f58f288c0994ba63c646bc1a8a22ad072e4e7e0a49f1c", - "sha256:ad32a981bcdedb8d2ace03b05e4fd8dace8901eec64a532b00b15217d3677dd2", - "sha256:aee9cf6b0134d6f932d219ce253ef0e624f4fa588ee64830fcba193269e4daa3", - "sha256:af05bbba896c4472a29408455fe31b3797b4d8648ed0a2ccac03e074a77e2314", - "sha256:b6cce5c76985f81da3769c52203ee94722cd5d5889731cd70d31fee939b74bf0", - "sha256:bb684694e99d0b791a43e9fc0fa58efc15ec357ac48d25b619f207c41f2fd384", - "sha256:c132b5a22821f9b143f87446805e13580b67c670a548b96da945a8f6b4f2efbb", - "sha256:c296263093f099da4f51b3dff1eff5d4959b527d4f2f419e16508c5da9e15e8c", - "sha256:c973b2fe4dc445cb865ab369df7521df9c27bf40715c837a113edaa2aa9faf45", - "sha256:cdd94501d65adc5c24f8a1a0eda110452ba62b3f4aeaba01e021c1ed9cb8f34a", - "sha256:d79d4826e41441c9a118ff045e4bccb9fdbdcb1d02413e7ea6eb5c87b5439d24", - "sha256:dbba8210f5067398b2c4d96b4e64d8fb943644d5eb70be0d989067c8ca40c0f8", - "sha256:df002e59f2d29e889c37abd0b9ee0d0e6e38c24f5f55d71ff0e09e3412a340ec", - "sha256:dfd14bcae0c94004baba5184d1c935ae0d1231b8409eb6c103a5fd75e8ecdc56", - "sha256:e25bacb53a8c7325e34d45dddd2f2fbae0dbc230d0e2642e264a64e17322a777", - "sha256:e2c8e3384c12dfa19fa9a52f23eb091a8fad93b5b81a41b14c17c78e23dd1d8b", - "sha256:e5f2a0f161d126ccc7038f1f3029184dbdf8f018230af17ef6fd6a707a5b881f", - "sha256:e69ad502f1a2243f739f5bd60565d14a278be58be4c137d90799f2c263e7049a", - "sha256:ead9b9605c54d15be228687552916c89c9683c215370c4a44f1f217d2adcc34d", - "sha256:f07ff574986bc3edb80e2c36391678a271d555f91fd1d332a1e0f4b5ea4b6ea9", - "sha256:f2c7a045eef561e9544359a0bf5784b44e55cefc7261a20e730baa9220c83413", - "sha256:f3e8796434a8106b3ac025fd15417315d7a58ee3e600ad4dbcfddc3f4b14342c", - "sha256:f63e21ed474edd23f7501f89b53280014436e383a14b9bd77a648366c81dce7b", - "sha256:fd49c01e5057a451c30c9b892948976f5d38f2cbd04dc556a82743ba8e27ed8c" + "sha256:093896e530c38c8e9c996901858ac63f3d4171268db2c9c8b373a228f459bbc5", + "sha256:09b9f848b28081e7b975a3626e9081574a7b9196cde26604540582da60235fdf", + "sha256:0b0c69f4f724c64dfbfe79f5dfb503b42fe6127b8d479b2677f2b227478db2eb", + "sha256:13618bed0c38acc418896005732e565b317aa9e98d855a0e9f211a7ffc2d6638", + "sha256:13690e923a3932e4fad4c0ebfb9cb5988e03d9dcb4c5150b5fcbf58fd8bddfc4", + "sha256:177f01eeaa3aee4a5ffb0d1439c5952b53d5010f86e9d2667963e632e30082cc", + "sha256:193e3bffca48ad74b8c764fb4492dd875038a2f9925530cb094db92bb5e47bed", + "sha256:1defe91d41ce1bd44b40fabf071e6a01a5aa14de4a31b986aa9dfd1b3e3e414a", + "sha256:1f188a2402f8359cf0c4b1fe89eea40dc13b52e7b4fd4812450da9fcd210181d", + "sha256:202a2d645c5a46b84992f55b0a3affe4f0ba6b4c611abec32ee88358db4bb649", + "sha256:24eda3a24a38157eee639ca9afe45eefa8d2420d49468819ac5f88b10de84f4c", + "sha256:2e4e0f60cb4bd7396108823548e82fdab72d4d8a65e58e2c19bbbc2f1e2bfa4b", + "sha256:379c111d3558272a2cae3d8e57e6b6e6f4fe652905692d54bad5ea0ca37c5ad4", + "sha256:37cda8712145917105e07aab96388ae76e787270ec04bcb9d5cc786d7cbb8443", + "sha256:38c51297b35b3ed91670e1e4efb702b790002e3245a28c76e627478aa3c10d83", + "sha256:3985b9be361d8fb6b2d1adc9924d01dec575a1d7453a14cccd73225cb79243ee", + "sha256:3988665ee376abce49613701336544041f2117de7b7fbfe91b93d8ff8b151c8e", + "sha256:3ac47fa29d8d41059ea3df65bd3ade92f97ee4910ed638e87075b8e8ce69599e", + "sha256:3b4b4299dd0d2c67caaaf286d58aef5e75b125b95615dda4542561a5a566a1e3", + "sha256:3ea8bb1ab9558374c0ab591783808511d135a833c3ca64a18ec927f20c4030f0", + "sha256:3fe47da3e4fda5f1abb5709c156eca207eacf8007304ce3019eb001e7a7204cb", + "sha256:428ac484592f780e8cd7b6b14eb568f7c85460c92e2a37cb0c0e5186e1a0d076", + "sha256:44e6c85bbdc809383b509d732b06419fb4544dca29ebe18480379633623baafb", + "sha256:4674f0daa1823c295845b6a740d98a840d7a1c11df00d1fd62614545c1583787", + "sha256:4be32da0c3827ac9132bb488d331cb32e8d9638dd41a0557c5569d57cf22c9c1", + "sha256:4db3ed6a907b555e57cc2e6f14dc3a4c2458cdad8919e40b5357ab9b6db6c43e", + "sha256:5c52a036535d12590c32c49209e79cabaad9f9ad8aa4cbd875b68c4d67a9cbce", + "sha256:629a1ba2115dce8bf75a5cce9f2486ae483cb89c0145795603d6554bdc83e801", + "sha256:62a66ff235e4c2e37ed3b6104d8b478d767ff73838d1222132a7a026aa548764", + "sha256:63068a11171e4276f6ece913bde059e77c713b48c3a848814a6537f35afb8365", + "sha256:63c19702db10ad79151a059d2d6336fe0c470f2e18d0d4d1a57f7f9713875dcf", + "sha256:644ec81edec0f4ad17d51c838a7d01e42811054543b76d4ba2c5d6af741ce2a6", + "sha256:6535d996f6537ecb298b4e287a855f37deaf64ff007162ec0afb9ab8ba3b8b71", + "sha256:6f4548c5ead23ad13fb7a2c8ea541357474ec13c2b736feb02e19a3085fac002", + "sha256:716a78a342679cd1177bc8c2fe957e0ab91405bd43a17094324845200b2fddf4", + "sha256:74610105ebd6f33d7c10f8907afed696e79c59e3043c5f20eaa3a46fddf33b4c", + "sha256:768939f7c4353c0fac2f7c37897e10b1414b571fd85dd9fc49e6a87e37a2e0d8", + "sha256:86cffe9c6dfcfe22e28027069725c7f57f4b868a3f86e81d1c62462764dc46d4", + "sha256:8aae5aea53cbfe024919715eca696b1a3201886ce83790537d1c3668459c7146", + "sha256:8b2b8503edb06822c86d82fa64a4a5cb0760bb8f31f26e138ec743f422f37cfc", + "sha256:912e95017ff51dc3d7b6e2be158dedc889d9a5cc3382445589ce554f1a34c0ea", + "sha256:9a7b8ac36fd688c8361cbc7bf1cb5866977ece6e0b17c34aa0df58bda4fa18a4", + "sha256:9e89d5c8509fbd6c03d0dd1972925b22f50db0792ce06324ba069f10787429ad", + "sha256:ae270e79f7e169ccfe23284ff5ea2d52a6f401dc01b337efb54b3783e2ce3f28", + "sha256:b07c25d52b1c16ce5de088046cd2432b30f9ad5e224ff17c8f496d9cb7d1d451", + "sha256:b39e6011cd06822eb964d038d5dff5da5d98652b81f5ecd439277b32361a3a50", + "sha256:bd55f8fc8fa494958772a2a7302b0354ab16e0b9272b3c3d83cdb5bec5bd1779", + "sha256:c15b32a7aca8038ed7644f854bf17b663bc38e1671b5d6f43f9a2b2bd0c46f63", + "sha256:c1b4474beee02ede1eef86c25ad4600a424fe36cff01a6103cb4533c6bf0169e", + "sha256:c79c0685f142ca53256722a384540832420dff4ab15fec1863d7e5bc8691bdcc", + "sha256:c9ebfb2507751f7196995142f057d1324afdab56db1d9743aab7f50289abd022", + "sha256:d7ad66e8e50225ebf4236368cc43c37f59d5e6728f15f6e258c8639fa0dd8e6d", + "sha256:d82ab6816c3277dc962cfcdc85b1efa0e5f50fb2c449432deaf2398a2928ab94", + "sha256:d9fd2547e6decdbf985d579cf3fc78e4c1d662b9b0ff7cc7862baaab71c9cc5b", + "sha256:de38add67a0af869b0d79c525d3e4588ac1ffa92f39116dbe0ed9753f26eba7d", + "sha256:e19122296822deafce89a0c5e8685704c067ae65d45e79718c92df7b3ec3d331", + "sha256:e44961e36cb13c495806d4cac67640ac2866cb99044e210895b506c26ee63d3a", + "sha256:e4c81ed2820b9023a9a90717020315e63b17b18c274a332e3b6437d7ff70abe0", + "sha256:e683e6ecc587643f8cde8f5da6768e9d165cd31edf39ee90ed7034f9ca0eefee", + "sha256:f39e2f3530ed1626c66e7493be7a8423b023ca852aacdc91fb30162c350d2a92", + "sha256:f56f49b2553d7dd85fd86e029515a221e5c1f8cb3d9c38b470bc38bde7b8445a", + "sha256:fb9fc32399dca861584d96eccd6c980b69bbcd7c228d06fb74fe53e007aa8ef9" ], "markers": "python_version >= '3.9'", - "version": "==7.6.7" + "version": "==7.6.8" }, "csvkit": { "hashes": [ @@ -1857,11 +2101,162 @@ }, "faker": { "hashes": [ - "sha256:68e5580cb6b4226710886e595eabc13127149d6e71e9d1db65506a7fbe2c7fce", - "sha256:9b01019c1ddaf2253ca2308c0472116e993f4ad8fc9905f82fa965e0c6f932e9" + "sha256:1c925fc0e86a51fc46648b504078c88d0cd48da1da2595c4e712841cab43a1e4", + "sha256:d30c5f0e2796b8970de68978365247657486eb0311c5abe88d0b895b68dff05d" ], "markers": "python_version >= '3.8'", - "version": "==33.0.0" + "version": "==33.1.0" + }, + "flask": { + "hashes": [ + "sha256:5f873c5184c897c8d9d1b05df1e3d01b14910ce69607a117bd3277098a5836ac", + "sha256:d667207822eb83f1c4b50949b1623c8fc8d51f2341d65f72e1a1815397551136" + ], + "markers": "python_version >= '3.9'", + "version": "==3.1.0" + }, + "flask-cors": { + "hashes": [ + "sha256:5aadb4b950c4e93745034594d9f3ea6591f734bb3662e16e255ffbf5e89c88ef", + "sha256:b9e307d082a9261c100d8fb0ba909eec6a228ed1b60a8315fd85f783d61910bc" + ], + "version": "==5.0.0" + }, + "flask-login": { + "hashes": [ + "sha256:5e23d14a607ef12806c699590b89d0f0e0d67baeec599d75947bf9c147330333", + "sha256:849b25b82a436bf830a054e74214074af59097171562ab10bfa999e6b78aae5d" + ], + "markers": "python_version >= '3.7'", + "version": "==0.6.3" + }, + "gevent": { + "hashes": [ + "sha256:1c3443b0ed23dcb7c36a748d42587168672953d368f2956b17fad36d43b58836", + "sha256:1d4fadc319b13ef0a3c44d2792f7918cf1bca27cacd4d41431c22e6b46668026", + "sha256:1ea50009ecb7f1327347c37e9eb6561bdbc7de290769ee1404107b9a9cba7cf1", + "sha256:2142704c2adce9cd92f6600f371afb2860a446bfd0be5bd86cca5b3e12130766", + "sha256:351d1c0e4ef2b618ace74c91b9b28b3eaa0dd45141878a964e03c7873af09f62", + "sha256:356b73d52a227d3313f8f828025b665deada57a43d02b1cf54e5d39028dbcf8d", + "sha256:3d882faa24f347f761f934786dde6c73aa6c9187ee710189f12dcc3a63ed4a50", + "sha256:58851f23c4bdb70390f10fc020c973ffcf409eb1664086792c8b1e20f25eef43", + "sha256:68bee86b6e1c041a187347ef84cf03a792f0b6c7238378bf6ba4118af11feaae", + "sha256:7398c629d43b1b6fd785db8ebd46c0a353880a6fab03d1cf9b6788e7240ee32e", + "sha256:816b3883fa6842c1cf9d2786722014a0fd31b6312cca1f749890b9803000bad6", + "sha256:81d918e952954675f93fb39001da02113ec4d5f4921bf5a0cc29719af6824e5d", + "sha256:85329d556aaedced90a993226d7d1186a539c843100d393f2349b28c55131c85", + "sha256:8619d5c888cb7aebf9aec6703e410620ef5ad48cdc2d813dd606f8aa7ace675f", + "sha256:8bd1419114e9e4a3ed33a5bad766afff9a3cf765cb440a582a1b3a9bc80c1aca", + "sha256:92e0d7759de2450a501effd99374256b26359e801b2d8bf3eedd3751973e87f5", + "sha256:92fe5dfee4e671c74ffaa431fd7ffd0ebb4b339363d24d0d944de532409b935e", + "sha256:97e2f3999a5c0656f42065d02939d64fffaf55861f7d62b0107a08f52c984897", + "sha256:9d3b249e4e1f40c598ab8393fc01ae6a3b4d51fc1adae56d9ba5b315f6b2d758", + "sha256:a3d75fa387b69c751a3d7c5c3ce7092a171555126e136c1d21ecd8b50c7a6e46", + "sha256:a5f1701ce0f7832f333dd2faf624484cbac99e60656bfbb72504decd42970f0f", + "sha256:b24d800328c39456534e3bc3e1684a28747729082684634789c2f5a8febe7671", + "sha256:b5efe72e99b7243e222ba0c2c2ce9618d7d36644c166d63373af239da1036bab", + "sha256:b7bfcfe08d038e1fa6de458891bca65c1ada6d145474274285822896a858c870", + "sha256:beede1d1cff0c6fafae3ab58a0c470d7526196ef4cd6cc18e7769f207f2ea4eb", + "sha256:c6b775381f805ff5faf250e3a07c0819529571d19bb2a9d474bee8c3f90d66af", + "sha256:c9c935b83d40c748b6421625465b7308d87c7b3717275acd587eef2bd1c39546", + "sha256:ca845138965c8c56d1550499d6b923eb1a2331acfa9e13b817ad8305dde83d11", + "sha256:d618e118fdb7af1d6c1a96597a5cd6ac84a9f3732b5be8515c6a66e098d498b6", + "sha256:d6c0a065e31ef04658f799215dddae8752d636de2bed61365c358f9c91e7af61", + "sha256:d740206e69dfdfdcd34510c20adcb9777ce2cc18973b3441ab9767cd8948ca8a", + "sha256:d7886b63ebfb865178ab28784accd32f287d5349b3ed71094c86e4d3ca738af5", + "sha256:d9347690f4e53de2c4af74e62d6fabc940b6d4a6cad555b5a379f61e7d3f2a8e", + "sha256:d9ca80711e6553880974898d99357fb649e062f9058418a92120ca06c18c3c59", + "sha256:e24181d172f50097ac8fc272c8c5b030149b630df02d1c639ee9f878a470ba2b", + "sha256:ec68e270543ecd532c4c1d70fca020f90aa5486ad49c4f3b8b2e64a66f5c9274", + "sha256:f43f47e702d0c8e1b8b997c00f1601486f9f976f84ab704f8f11536e3fa144c9", + "sha256:ff96c5739834c9a594db0e12bf59cb3fa0e5102fc7b893972118a3166733d61c" + ], + "markers": "python_version >= '3.9'", + "version": "==24.11.1" + }, + "geventhttpclient": { + "hashes": [ + "sha256:032b4c519b5e7022c9563dbc7d1fac21ededb49f9e46ff2a9c44d1095747d2ea", + "sha256:0b1a60f810896a3e59a0e1036aa8fc31478e1ec0dd3faac7a771dd3d956580ce", + "sha256:0d99d09fc20e91902a7b81000d4b819c4da1d5911b2452e948bffd00dbd3722e", + "sha256:0e30bb1f0e754720ecbacf353db054ba1c3fa01d6016d00978eeed60b066703b", + "sha256:0fbaedf4227f3691bc9e1080f42ebdf1b4131fc5aa09b00ed3934626197a9fbe", + "sha256:12354718a63e2314c6dd1a6cd4d65cb0db7423062fb0aaaf1dee258cfa51e795", + "sha256:14664f4a2d0296d6be5b65b6e57627987e0c2ecffd0ae6d7f9160bf119e8d728", + "sha256:1ad896af16ffa276620f4f555ef057fe11a2aa6af21dc0136600d0b7738e67ae", + "sha256:1fbfeea0242f30b9bfd2e982fc82aa2977eeef17e2526a681f7e8e1e37b2569a", + "sha256:2209e77a101ae67d3355d506f65257908f1eb41db74f765b01cb191e4a5160d5", + "sha256:29fe3b6523efa8cdcb5e9bad379f9055e4f0ebb914e4dcd8a0ca33b003b402f5", + "sha256:34622d675af26d9289d6bd5f03721cedc01db3ed99e1244360b48c73228d113c", + "sha256:35a6de7088ad69ba1561deaf854bf34c78a0eee33027b24aa7c44cdbe840b1d8", + "sha256:36f9a4c93eb8927376c995cc91857a1e94dd4a68a0c459870adb11799ceea75d", + "sha256:386f0c9215958b9c974031fdbaa84002b4291b67bfe6dc5833cfb6e28083bb95", + "sha256:3b5eba36ea0ad819386e3850a71a42af53e6b9be86d4605d6ded061503573928", + "sha256:3e74c1570d01dd09cabdfe2667fbf072520ec9bb3a31a0fd1eae3d0f43847f9b", + "sha256:447fc2d49a41449684154c12c03ab80176a413e9810d974363a061b71bdbf5a0", + "sha256:452c3c2c15830fc0be7ea76c6d98f49df0a94327fbdd63822a840ad3125796dc", + "sha256:4598c2aa14c866a10a07a2944e2c212f53d0c337ce211336ad68ae8243646216", + "sha256:493d5deb230e28fdd8d0d0f8e7addb4e7b9761e6a1115ea72f22b231835e546b", + "sha256:49512144af09fb2438a3e14e14863e7556434be3676efdaa0379198ce38bf1e2", + "sha256:4a942448e77c01286edc4c29c22575d701d0639d42d0061b37025e118129372a", + "sha256:4d6ae4ce130bf91cbdbab951b39a5faeb82b50f37a027afaac1cc956b344cc5d", + "sha256:4fc1d824602d9590a2b88ac14cfe6d2ecc357e91472ecfe719973c40aab25f4e", + "sha256:50c62dbe5f43c9e0ee43f872de44aebf4968695d90804d71fc1bf32b827fae16", + "sha256:52450392f3b9d32563c685013ba30b028f948612ebb9b1bfd6ba4ae113d985dc", + "sha256:53033fc1aac51b7513858662d8e17f44aa05207c3772d69fb1a07e2c5a2e45e4", + "sha256:566d7fb431d416bfb0cc431ec74062858133ee94b5001e32f9607a9433cc1e4f", + "sha256:5865be94cf03aa219ff4d6fe3a01be798f1205d7d9611e51e75f2606c7c9ae35", + "sha256:61b34527938e3ab477ecc90ec6bcde9780468722abececf548cbae89e4cd9d0b", + "sha256:6552c4d91c38007824f43a13fbbf4c615b7c6abe94fc2d482752ea91d976e140", + "sha256:69d2bd7ab7f94a6c73325f4b88fd07b0d5f4865672ed7a519f2d896949353761", + "sha256:6bbab6fef671cc7268cd54f9d018a703542ec767998da0164bb61eb789f8d069", + "sha256:72011601bcd0952a8f4188893307dc0263f96e967126bc4df2e15d2f74fa4622", + "sha256:795ad495865fc535ceb19908c5b0b468d6ccf94b44c3c3229cae85616da400ab", + "sha256:7a00e130577c0cf9749d1143e71543c50c7103321b7f37afc42782ad1d3c0ef7", + "sha256:7a3182f1457599c2901c48a1def37a5bc4762f696077e186e2050fcc60b2fbdf", + "sha256:82f16cf2fd71e6b77e6153a66aae282da00958b43345879e222605a3a7556e3a", + "sha256:86b489238dc2cbfa53cdd5621e888786a53031d327e0a8509529c7568292b0ce", + "sha256:8b78a8e5ff3c06dfee63b8457740c1d7d2f0687f85ded76dfca2b25f52200a1c", + "sha256:8bba80efc5c95e94641dc3e9864ab37829111a4e90bdf2ef08b1206c7a89dd94", + "sha256:8fdfcf45166cecdade78d3dcb9c7615793269fa3d2d7fea328fe007bd87d84c6", + "sha256:93e9c4f27d48ce4da6dde530aea00e8d427965ace0801fe3d7c4739e167c10de", + "sha256:947e4f511e45abcc24fc982cee6042d14dc765d1a9ebd3c660cb93714002f950", + "sha256:98bfa7cf5b6246b28e05a72505211b60a6ecb63c934dd70b806e662869b009f6", + "sha256:a36145c0b34d3c0e8c0c4a9d2e6d6f2b9f382c12e698fadb6a646a9b320a6c69", + "sha256:a4d4f777a9b55d6babbf5525623ad74e543e6fbb86bc3305bf24d80fcc0190dc", + "sha256:a6dea544c829894366cfaa4d36a2014557a99f8769c9dd7b8fbf9b607126e04a", + "sha256:a8519b9aacad25696a220c1217047d5277403df96cb8aa8e9a5ec5271798cb87", + "sha256:a96e96b63ddcea3d25f62b204aafb523782ff0fcf45b38eb596f8ae4a0f17326", + "sha256:aa56b2b0477b4b9c325251c1672d29762d08c5d2ad8d9e5db0b8279872e0030d", + "sha256:aadaabe9267aacec88912ae5ac84b232e16a0ed12c5256559637f4b74aa510e8", + "sha256:aafdd67e7c4163f0245e1785c1dc42b2f4fdaacae1f28c68758f06010335f93c", + "sha256:acccefebf3b1cc81f90d384dd17c1b3b58deee5ea1891025ef409307a22036b6", + "sha256:b1ee31fed440029e20c99c89e49a0f983b771e7529db81fab33d942193036c41", + "sha256:b29e1383725d99e583e8ad125cfa820b8368ae7cfad642167bca869f55c4b000", + "sha256:b366bf38dd5335868a2ea077091af707c1111f70ee4cc8aa60dc14f56928158e", + "sha256:c02e50baf4589c7b35db0f96fae7f3bd7e2dfbed2e1a2c1a0aa5696b91dff889", + "sha256:c16830c9cad42c50f87e939f8065dc922010bbcbfb801fa12fd74d091dae7bef", + "sha256:c2586f3c2602cde0c3e5345813c0ab461142d1522667436b04d8a7dd7e7576c8", + "sha256:c4c8aca6ab5da4211870c1d8410c699a9d543e86304aac47e1558ec94d0da97a", + "sha256:c8831f3ff03c11f64ad3b306883a8b064ef75f16a9f6a85cd105286023fba030", + "sha256:caf12944df25318a8c5b4deebc35ac94951562da154f039712ae3cde40ec5d95", + "sha256:cbfcb54ee015aa38c8e9eb3bb4be68f88fbce6cbf90f716fc3ffc5f49892f721", + "sha256:cf1051cc18521cd0819d3d69d930a4de916fb6f62be829b675481ca47e960765", + "sha256:d0248bbc2ff430dc2bec89e44715e4a38c7f2097ad2a133ca190f74fee51e5ef", + "sha256:d1642c8b3042b675a5b7ad67bce9611415d7bce0cf0380c0be52b7e5f55bc3e8", + "sha256:d3a52ee992488ff087a3ec99d0076541ba1b07464c8eac22ad1a7778860bc345", + "sha256:d61cad95f80d5bd599e28933c187b3c4eeb0b2f6306e06fa0edcac5c9c4bac0a", + "sha256:d686ce9ad28ddcb36b7748a59e64e2d8acfaa0145f0817becace36b1cfa4e5c6", + "sha256:dc77b39246ba5d2484567100377f100e4aa50b6b8849d3e547d68dc0138087dd", + "sha256:e32313c833dfbe27d3f66feacac667ae937859dbbd58e25d1172329c8b368426", + "sha256:e4b503183be80a1fb027eb5582413ca2be60356a7cf8eb9d49b913703f4ecd93", + "sha256:e5a14dd4e3504f05fc9febaedcb7cc91222da7176a6a9a2e703ab0cd85444016", + "sha256:f062f4120661c25cc87b7cbec1c4b27e83f618604d1403e950191835b999a61a", + "sha256:f5724370d95ce9753846ff90d7805a11f7981d9dc579e3a229fa594cb401da98", + "sha256:f584fa36981b8a93799c63226a3deb385d1cc4f19eacd5dd6c696da0ecb4cca6" + ], + "markers": "python_version >= '3.9'", + "version": "==2.3.3" }, "greenlet": { "hashes": [ @@ -2001,6 +2396,22 @@ "markers": "python_version >= '3.7'", "version": "==0.7.2" }, + "itsdangerous": { + "hashes": [ + "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", + "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173" + ], + "markers": "python_version >= '3.8'", + "version": "==2.2.0" + }, + "jinja2": { + "hashes": [ + "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", + "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.4" + }, "leather": { "hashes": [ "sha256:18290bc93749ae39039af5e31e871fcfad74d26c4c3ea28ea4f681f4571b3a2b", @@ -2008,6 +2419,152 @@ ], "version": "==0.4.0" }, + "locust": { + "hashes": [ + "sha256:54a4ec106ec0ee79305deda4659b3f325c1e87b134face75d5da6525adde6316", + "sha256:d2920bc7f19d7f3bedee6cc2cafddc547ba128cba51e5e339c308e14fb88f1a7" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==2.32.2" + }, + "markupsafe": { + "hashes": [ + "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", + "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", + "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0", + "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", + "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", + "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13", + "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", + "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", + "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", + "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", + "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0", + "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", + "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", + "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", + "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", + "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff", + "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", + "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", + "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", + "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", + "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", + "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", + "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", + "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", + "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a", + "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", + "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", + "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", + "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", + "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144", + "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f", + "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", + "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", + "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", + "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", + "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", + "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", + "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", + "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", + "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", + "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", + "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", + "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", + "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", + "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", + "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", + "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", + "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", + "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29", + "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", + "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", + "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", + "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", + "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", + "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", + "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a", + "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178", + "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", + "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", + "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", + "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50" + ], + "markers": "python_version >= '3.9'", + "version": "==3.0.2" + }, + "msgpack": { + "hashes": [ + "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b", + "sha256:071603e2f0771c45ad9bc65719291c568d4edf120b44eb36324dcb02a13bfddf", + "sha256:0907e1a7119b337971a689153665764adc34e89175f9a34793307d9def08e6ca", + "sha256:0f92a83b84e7c0749e3f12821949d79485971f087604178026085f60ce109330", + "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f", + "sha256:13599f8829cfbe0158f6456374e9eea9f44eee08076291771d8ae93eda56607f", + "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39", + "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247", + "sha256:3180065ec2abbe13a4ad37688b61b99d7f9e012a535b930e0e683ad6bc30155b", + "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c", + "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7", + "sha256:3df7e6b05571b3814361e8464f9304c42d2196808e0119f55d0d3e62cd5ea044", + "sha256:41c991beebf175faf352fb940bf2af9ad1fb77fd25f38d9142053914947cdbf6", + "sha256:42f754515e0f683f9c79210a5d1cad631ec3d06cea5172214d2176a42e67e19b", + "sha256:452aff037287acb1d70a804ffd022b21fa2bb7c46bee884dbc864cc9024128a0", + "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2", + "sha256:46c34e99110762a76e3911fc923222472c9d681f1094096ac4102c18319e6468", + "sha256:471e27a5787a2e3f974ba023f9e265a8c7cfd373632247deb225617e3100a3c7", + "sha256:4a1964df7b81285d00a84da4e70cb1383f2e665e0f1f2a7027e683956d04b734", + "sha256:4b51405e36e075193bc051315dbf29168d6141ae2500ba8cd80a522964e31434", + "sha256:4d1b7ff2d6146e16e8bd665ac726a89c74163ef8cd39fa8c1087d4e52d3a2325", + "sha256:53258eeb7a80fc46f62fd59c876957a2d0e15e6449a9e71842b6d24419d88ca1", + "sha256:534480ee5690ab3cbed89d4c8971a5c631b69a8c0883ecfea96c19118510c846", + "sha256:58638690ebd0a06427c5fe1a227bb6b8b9fdc2bd07701bec13c2335c82131a88", + "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420", + "sha256:59caf6a4ed0d164055ccff8fe31eddc0ebc07cf7326a2aaa0dbf7a4001cd823e", + "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2", + "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59", + "sha256:646afc8102935a388ffc3914b336d22d1c2d6209c773f3eb5dd4d6d3b6f8c1cb", + "sha256:64fc9068d701233effd61b19efb1485587560b66fe57b3e50d29c5d78e7fef68", + "sha256:65553c9b6da8166e819a6aa90ad15288599b340f91d18f60b2061f402b9a4915", + "sha256:685ec345eefc757a7c8af44a3032734a739f8c45d1b0ac45efc5d8977aa4720f", + "sha256:6ad622bf7756d5a497d5b6836e7fc3752e2dd6f4c648e24b1803f6048596f701", + "sha256:73322a6cc57fcee3c0c57c4463d828e9428275fb85a27aa2aa1a92fdc42afd7b", + "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d", + "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa", + "sha256:7a946a8992941fea80ed4beae6bff74ffd7ee129a90b4dd5cf9c476a30e9708d", + "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd", + "sha256:7c9a35ce2c2573bada929e0b7b3576de647b0defbd25f5139dcdaba0ae35a4cc", + "sha256:7e7b853bbc44fb03fbdba34feb4bd414322180135e2cb5164f20ce1c9795ee48", + "sha256:879a7b7b0ad82481c52d3c7eb99bf6f0645dbdec5134a4bddbd16f3506947feb", + "sha256:8a706d1e74dd3dea05cb54580d9bd8b2880e9264856ce5068027eed09680aa74", + "sha256:8a84efb768fb968381e525eeeb3d92857e4985aacc39f3c47ffd00eb4509315b", + "sha256:8cf9e8c3a2153934a23ac160cc4cba0ec035f6867c8013cc6077a79823370346", + "sha256:8da4bf6d54ceed70e8861f833f83ce0814a2b72102e890cbdfe4b34764cdd66e", + "sha256:8e59bca908d9ca0de3dc8684f21ebf9a690fe47b6be93236eb40b99af28b6ea6", + "sha256:914571a2a5b4e7606997e169f64ce53a8b1e06f2cf2c3a7273aa106236d43dd5", + "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f", + "sha256:a52a1f3a5af7ba1c9ace055b659189f6c669cf3657095b50f9602af3a3ba0fe5", + "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b", + "sha256:b4c01941fd2ff87c2a934ee6055bda4ed353a7846b8d4f341c428109e9fcde8c", + "sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f", + "sha256:c40ffa9a15d74e05ba1fe2681ea33b9caffd886675412612d93ab17b58ea2fec", + "sha256:c5a91481a3cc573ac8c0d9aace09345d989dc4a0202b7fcb312c88c26d4e71a8", + "sha256:c921af52214dcbb75e6bdf6a661b23c3e6417f00c603dd2070bccb5c3ef499f5", + "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d", + "sha256:d8ce0b22b890be5d252de90d0e0d119f363012027cf256185fc3d474c44b1b9e", + "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e", + "sha256:e0856a2b7e8dcb874be44fea031d22e5b3a19121be92a1e098f46068a11b0870", + "sha256:e1f3c3d21f7cf67bcf2da8e494d30a75e4cf60041d98b3f79875afb5b96f3a3f", + "sha256:f1ba6136e650898082d9d5a5217d5906d1e138024f836ff48691784bbe1adf96", + "sha256:f3e9b4936df53b970513eac1758f3882c88658a220b58dcc1e39606dccaaf01c", + "sha256:f80bc7d47f76089633763f952e67f8214cb7b3ee6bfa489b3cb6a84cfac114cd", + "sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788" + ], + "markers": "python_version >= '3.8'", + "version": "==1.1.0" + }, "mypy": { "hashes": [ "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc", @@ -2189,6 +2746,29 @@ "markers": "python_version >= '3.8' and python_version < '4.0'", "version": "==2.17.0" }, + "psutil": { + "hashes": [ + "sha256:000d1d1ebd634b4efb383f4034437384e44a6d455260aaee2eca1e9c1b55f047", + "sha256:045f00a43c737f960d273a83973b2511430d61f283a44c96bf13a6e829ba8fdc", + "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", + "sha256:1209036fbd0421afde505a4879dee3b2fd7b1e14fee81c0069807adcbbcca747", + "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", + "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", + "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", + "sha256:5cd2bcdc75b452ba2e10f0e8ecc0b57b827dd5d7aaffbc6821b2a9a242823a76", + "sha256:6d3fbbc8d23fcdcb500d2c9f94e07b1342df8ed71b948a2649b5cb060a7c94ca", + "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", + "sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e", + "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", + "sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85", + "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", + "sha256:c0e0c00aa18ca2d3b2b991643b799a15fc8f0563d2ebb6040f64ce8dc027b942", + "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", + "sha256:ff34df86226c0227c52f38b919213157588a678d049688eded74c76c8ba4a5d0" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", + "version": "==6.1.0" + }, "pytest": { "hashes": [ "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", @@ -2239,6 +2819,133 @@ ], "version": "==1.1.8" }, + "pyzmq": { + "hashes": [ + "sha256:007137c9ac9ad5ea21e6ad97d3489af654381324d5d3ba614c323f60dab8fae6", + "sha256:034da5fc55d9f8da09015d368f519478a52675e558c989bfcb5cf6d4e16a7d2a", + "sha256:05590cdbc6b902101d0e65d6a4780af14dc22914cc6ab995d99b85af45362cc9", + "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f", + "sha256:0aca98bc423eb7d153214b2df397c6421ba6373d3397b26c057af3c904452e37", + "sha256:0bed0e799e6120b9c32756203fb9dfe8ca2fb8467fed830c34c877e25638c3fc", + "sha256:0d987a3ae5a71c6226b203cfd298720e0086c7fe7c74f35fa8edddfbd6597eed", + "sha256:0eaa83fc4c1e271c24eaf8fb083cbccef8fde77ec8cd45f3c35a9a123e6da097", + "sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d", + "sha256:17bf5a931c7f6618023cdacc7081f3f266aecb68ca692adac015c383a134ca52", + "sha256:17c412bad2eb9468e876f556eb4ee910e62d721d2c7a53c7fa31e643d35352e6", + "sha256:18c8dc3b7468d8b4bdf60ce9d7141897da103c7a4690157b32b60acb45e333e6", + "sha256:1a534f43bc738181aa7cbbaf48e3eca62c76453a40a746ab95d4b27b1111a7d2", + "sha256:1c17211bc037c7d88e85ed8b7d8f7e52db6dc8eca5590d162717c654550f7282", + "sha256:1f3496d76b89d9429a656293744ceca4d2ac2a10ae59b84c1da9b5165f429ad3", + "sha256:1fcc03fa4997c447dce58264e93b5aa2d57714fbe0f06c07b7785ae131512732", + "sha256:226af7dcb51fdb0109f0016449b357e182ea0ceb6b47dfb5999d569e5db161d5", + "sha256:23f4aad749d13698f3f7b64aad34f5fc02d6f20f05999eebc96b89b01262fb18", + "sha256:25bf2374a2a8433633c65ccb9553350d5e17e60c8eb4de4d92cc6bd60f01d306", + "sha256:28ad5233e9c3b52d76196c696e362508959741e1a005fb8fa03b51aea156088f", + "sha256:28c812d9757fe8acecc910c9ac9dafd2ce968c00f9e619db09e9f8f54c3a68a3", + "sha256:29c6a4635eef69d68a00321e12a7d2559fe2dfccfa8efae3ffb8e91cd0b36a8b", + "sha256:29c7947c594e105cb9e6c466bace8532dc1ca02d498684128b339799f5248277", + "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a", + "sha256:2ae90ff9dad33a1cfe947d2c40cb9cb5e600d759ac4f0fd22616ce6540f72797", + "sha256:2c4a71d5d6e7b28a47a394c0471b7e77a0661e2d651e7ae91e0cab0a587859ca", + "sha256:2ea4ad4e6a12e454de05f2949d4beddb52460f3de7c8b9d5c46fbb7d7222e02c", + "sha256:2eb7735ee73ca1b0d71e0e67c3739c689067f055c764f73aac4cc8ecf958ee3f", + "sha256:31507f7b47cc1ead1f6e86927f8ebb196a0bab043f6345ce070f412a59bf87b5", + "sha256:35cffef589bcdc587d06f9149f8d5e9e8859920a071df5a2671de2213bef592a", + "sha256:367b4f689786fca726ef7a6c5ba606958b145b9340a5e4808132cc65759abd44", + "sha256:39887ac397ff35b7b775db7201095fc6310a35fdbae85bac4523f7eb3b840e20", + "sha256:3a495b30fc91db2db25120df5847d9833af237546fd59170701acd816ccc01c4", + "sha256:3b55a4229ce5da9497dd0452b914556ae58e96a4381bb6f59f1305dfd7e53fc8", + "sha256:402b190912935d3db15b03e8f7485812db350d271b284ded2b80d2e5704be780", + "sha256:43a47408ac52647dfabbc66a25b05b6a61700b5165807e3fbd40063fcaf46386", + "sha256:4661c88db4a9e0f958c8abc2b97472e23061f0bc737f6f6179d7a27024e1faa5", + "sha256:46a446c212e58456b23af260f3d9fb785054f3e3653dbf7279d8f2b5546b21c2", + "sha256:470d4a4f6d48fb34e92d768b4e8a5cc3780db0d69107abf1cd7ff734b9766eb0", + "sha256:49d34ab71db5a9c292a7644ce74190b1dd5a3475612eefb1f8be1d6961441971", + "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b", + "sha256:4d80b1dd99c1942f74ed608ddb38b181b87476c6a966a88a950c7dee118fdf50", + "sha256:4da04c48873a6abdd71811c5e163bd656ee1b957971db7f35140a2d573f6949c", + "sha256:4f78c88905461a9203eac9faac157a2a0dbba84a0fd09fd29315db27be40af9f", + "sha256:4ff9dc6bc1664bb9eec25cd17506ef6672d506115095411e237d571e92a58231", + "sha256:5506f06d7dc6ecf1efacb4a013b1f05071bb24b76350832c96449f4a2d95091c", + "sha256:55cf66647e49d4621a7e20c8d13511ef1fe1efbbccf670811864452487007e08", + "sha256:5a509df7d0a83a4b178d0f937ef14286659225ef4e8812e05580776c70e155d5", + "sha256:5c2b3bfd4b9689919db068ac6c9911f3fcb231c39f7dd30e3138be94896d18e6", + "sha256:6835dd60355593de10350394242b5757fbbd88b25287314316f266e24c61d073", + "sha256:689c5d781014956a4a6de61d74ba97b23547e431e9e7d64f27d4922ba96e9d6e", + "sha256:6a96179a24b14fa6428cbfc08641c779a53f8fcec43644030328f44034c7f1f4", + "sha256:6ace4f71f1900a548f48407fc9be59c6ba9d9aaf658c2eea6cf2779e72f9f317", + "sha256:6b274e0762c33c7471f1a7471d1a2085b1a35eba5cdc48d2ae319f28b6fc4de3", + "sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072", + "sha256:70fc7fcf0410d16ebdda9b26cbd8bf8d803d220a7f3522e060a69a9c87bf7bad", + "sha256:7133d0a1677aec369d67dd78520d3fa96dd7f3dcec99d66c1762870e5ea1a50a", + "sha256:7445be39143a8aa4faec43b076e06944b8f9d0701b669df4af200531b21e40bb", + "sha256:76589c020680778f06b7e0b193f4b6dd66d470234a16e1df90329f5e14a171cd", + "sha256:76589f2cd6b77b5bdea4fca5992dc1c23389d68b18ccc26a53680ba2dc80ff2f", + "sha256:77eb0968da535cba0470a5165468b2cac7772cfb569977cff92e240f57e31bef", + "sha256:794a4562dcb374f7dbbfb3f51d28fb40123b5a2abadee7b4091f93054909add5", + "sha256:7ad1bc8d1b7a18497dda9600b12dc193c577beb391beae5cd2349184db40f187", + "sha256:7f98f6dfa8b8ccaf39163ce872bddacca38f6a67289116c8937a02e30bbe9711", + "sha256:8423c1877d72c041f2c263b1ec6e34360448decfb323fa8b94e85883043ef988", + "sha256:8685fa9c25ff00f550c1fec650430c4b71e4e48e8d852f7ddcf2e48308038640", + "sha256:878206a45202247781472a2d99df12a176fef806ca175799e1c6ad263510d57c", + "sha256:89289a5ee32ef6c439086184529ae060c741334b8970a6855ec0b6ad3ff28764", + "sha256:8ab5cad923cc95c87bffee098a27856c859bd5d0af31bd346035aa816b081fe1", + "sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1", + "sha256:8be4700cd8bb02cc454f630dcdf7cfa99de96788b80c51b60fe2fe1dac480289", + "sha256:8c997098cc65e3208eca09303630e84d42718620e83b733d0fd69543a9cab9cb", + "sha256:8ea039387c10202ce304af74def5021e9adc6297067f3441d348d2b633e8166a", + "sha256:8f7e66c7113c684c2b3f1c83cdd3376103ee0ce4c49ff80a648643e57fb22218", + "sha256:90412f2db8c02a3864cbfc67db0e3dcdbda336acf1c469526d3e869394fe001c", + "sha256:92a78853d7280bffb93df0a4a6a2498cba10ee793cc8076ef797ef2f74d107cf", + "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7", + "sha256:9cb3a6460cdea8fe8194a76de8895707e61ded10ad0be97188cc8463ffa7e3a8", + "sha256:9dd8cd1aeb00775f527ec60022004d030ddc51d783d056e3e23e74e623e33726", + "sha256:9ed69074a610fad1c2fda66180e7b2edd4d31c53f2d1872bc2d1211563904cd9", + "sha256:9edda2df81daa129b25a39b86cb57dfdfe16f7ec15b42b19bfac503360d27a93", + "sha256:a2224fa4a4c2ee872886ed00a571f5e967c85e078e8e8c2530a2fb01b3309b88", + "sha256:a4f96f0d88accc3dbe4a9025f785ba830f968e21e3e2c6321ccdfc9aef755115", + "sha256:aedd5dd8692635813368e558a05266b995d3d020b23e49581ddd5bbe197a8ab6", + "sha256:aee22939bb6075e7afededabad1a56a905da0b3c4e3e0c45e75810ebe3a52672", + "sha256:b1d464cb8d72bfc1a3adc53305a63a8e0cac6bc8c5a07e8ca190ab8d3faa43c2", + "sha256:b8f86dd868d41bea9a5f873ee13bf5551c94cf6bc51baebc6f85075971fe6eea", + "sha256:bc6bee759a6bddea5db78d7dcd609397449cb2d2d6587f48f3ca613b19410cfc", + "sha256:bea2acdd8ea4275e1278350ced63da0b166421928276c7c8e3f9729d7402a57b", + "sha256:bfa832bfa540e5b5c27dcf5de5d82ebc431b82c453a43d141afb1e5d2de025fa", + "sha256:c0e6091b157d48cbe37bd67233318dbb53e1e6327d6fc3bb284afd585d141003", + "sha256:c3789bd5768ab5618ebf09cef6ec2b35fed88709b104351748a63045f0ff9797", + "sha256:c530e1eecd036ecc83c3407f77bb86feb79916d4a33d11394b8234f3bd35b940", + "sha256:c811cfcd6a9bf680236c40c6f617187515269ab2912f3d7e8c0174898e2519db", + "sha256:c92d73464b886931308ccc45b2744e5968cbaade0b1d6aeb40d8ab537765f5bc", + "sha256:cccba051221b916a4f5e538997c45d7d136a5646442b1231b916d0164067ea27", + "sha256:cdeabcff45d1c219636ee2e54d852262e5c2e085d6cb476d938aee8d921356b3", + "sha256:ced65e5a985398827cc9276b93ef6dfabe0273c23de8c7931339d7e141c2818e", + "sha256:d049df610ac811dcffdc147153b414147428567fbbc8be43bb8885f04db39d98", + "sha256:dacd995031a01d16eec825bf30802fceb2c3791ef24bcce48fa98ce40918c27b", + "sha256:ddf33d97d2f52d89f6e6e7ae66ee35a4d9ca6f36eda89c24591b0c40205a3629", + "sha256:ded0fc7d90fe93ae0b18059930086c51e640cdd3baebdc783a695c77f123dcd9", + "sha256:e3e0210287329272539eea617830a6a28161fbbd8a3271bf4150ae3e58c5d0e6", + "sha256:e6fa2e3e683f34aea77de8112f6483803c96a44fd726d7358b9888ae5bb394ec", + "sha256:ea0eb6af8a17fa272f7b98d7bebfab7836a0d62738e16ba380f440fceca2d951", + "sha256:ea7f69de383cb47522c9c208aec6dd17697db7875a4674c4af3f8cfdac0bdeae", + "sha256:eac5174677da084abf378739dbf4ad245661635f1600edd1221f150b165343f4", + "sha256:fc4f7a173a5609631bb0c42c23d12c49df3966f89f496a51d3eb0ec81f4519d6", + "sha256:fdb5b3e311d4d4b0eb8b3e8b4d1b0a512713ad7e6a68791d0923d1aec433d919" + ], + "markers": "python_version >= '3.7'", + "version": "==26.2.0" + }, + "qualicharge": { + "editable": true, + "path": "." + }, + "requests": { + "hashes": [ + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" + ], + "markers": "python_version >= '3.8'", + "version": "==2.32.3" + }, "ruff": { "hashes": [ "sha256:00b4cf3a6b5fad6d1a66e7574d78956bbd09abfd6c8a997798f01f5da3d46a05", @@ -2264,6 +2971,15 @@ "markers": "python_version >= '3.7'", "version": "==0.7.4" }, + "setuptools": { + "hashes": [ + "sha256:5c4ccb41111392671f02bb5f8436dfc5a9a7185e80500531b133f5775c4163ef", + "sha256:87cb777c3b96d638ca02031192d40390e0ad97737e27b6b4fa831bea86f2f829" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==75.5.0" + }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", @@ -2384,6 +3100,15 @@ "markers": "python_version >= '3.8'", "version": "==2024.2.0.20241003" }, + "types-requests": { + "hashes": [ + "sha256:0d9cad2f27515d0e3e3da7134a1b6f28fb97129d86b867f24d9c726452634d95", + "sha256:4195d62d6d3e043a4eaaf08ff8a62184584d2e8684e9d2aa178c7915a7da3747" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.32.0.20241016" + }, "typing-extensions": { "hashes": [ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", @@ -2392,6 +3117,22 @@ "markers": "python_version >= '3.8'", "version": "==4.12.2" }, + "urllib3": { + "hashes": [ + "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", + "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" + ], + "markers": "python_version >= '3.8'", + "version": "==2.2.3" + }, + "werkzeug": { + "hashes": [ + "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", + "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746" + ], + "markers": "python_version >= '3.9'", + "version": "==3.1.3" + }, "xlrd": { "hashes": [ "sha256:6a33ee89877bd9abc1158129f6e94be74e2679636b8a205b43b85206c3f0bbdd", @@ -2399,6 +3140,57 @@ ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", "version": "==2.0.1" + }, + "zope.event": { + "hashes": [ + "sha256:2832e95014f4db26c47a13fdaef84cef2f4df37e66b59d8f1f4a8f319a632c26", + "sha256:bac440d8d9891b4068e2b5a2c5e2c9765a9df762944bda6955f96bb9b91e67cd" + ], + "markers": "python_version >= '3.7'", + "version": "==5.0" + }, + "zope.interface": { + "hashes": [ + "sha256:033b3923b63474800b04cba480b70f6e6243a62208071fc148354f3f89cc01b7", + "sha256:05b910a5afe03256b58ab2ba6288960a2892dfeef01336dc4be6f1b9ed02ab0a", + "sha256:086ee2f51eaef1e4a52bd7d3111a0404081dadae87f84c0ad4ce2649d4f708b7", + "sha256:0ef9e2f865721553c6f22a9ff97da0f0216c074bd02b25cf0d3af60ea4d6931d", + "sha256:1090c60116b3da3bfdd0c03406e2f14a1ff53e5771aebe33fec1edc0a350175d", + "sha256:144964649eba4c5e4410bb0ee290d338e78f179cdbfd15813de1a664e7649b3b", + "sha256:15398c000c094b8855d7d74f4fdc9e73aa02d4d0d5c775acdef98cdb1119768d", + "sha256:1909f52a00c8c3dcab6c4fad5d13de2285a4b3c7be063b239b8dc15ddfb73bd2", + "sha256:21328fcc9d5b80768bf051faa35ab98fb979080c18e6f84ab3f27ce703bce465", + "sha256:224b7b0314f919e751f2bca17d15aad00ddbb1eadf1cb0190fa8175edb7ede62", + "sha256:25e6a61dcb184453bb00eafa733169ab6d903e46f5c2ace4ad275386f9ab327a", + "sha256:27f926f0dcb058211a3bb3e0e501c69759613b17a553788b2caeb991bed3b61d", + "sha256:29caad142a2355ce7cfea48725aa8bcf0067e2b5cc63fcf5cd9f97ad12d6afb5", + "sha256:2ad9913fd858274db8dd867012ebe544ef18d218f6f7d1e3c3e6d98000f14b75", + "sha256:31d06db13a30303c08d61d5fb32154be51dfcbdb8438d2374ae27b4e069aac40", + "sha256:3e0350b51e88658d5ad126c6a57502b19d5f559f6cb0a628e3dc90442b53dd98", + "sha256:3f6771d1647b1fc543d37640b45c06b34832a943c80d1db214a37c31161a93f1", + "sha256:4893395d5dd2ba655c38ceb13014fd65667740f09fa5bb01caa1e6284e48c0cd", + "sha256:52e446f9955195440e787596dccd1411f543743c359eeb26e9b2c02b077b0519", + "sha256:550f1c6588ecc368c9ce13c44a49b8d6b6f3ca7588873c679bd8fd88a1b557b6", + "sha256:72cd1790b48c16db85d51fbbd12d20949d7339ad84fd971427cf00d990c1f137", + "sha256:7bd449c306ba006c65799ea7912adbbfed071089461a19091a228998b82b1fdb", + "sha256:7dc5016e0133c1a1ec212fc87a4f7e7e562054549a99c73c8896fa3a9e80cbc7", + "sha256:802176a9f99bd8cc276dcd3b8512808716492f6f557c11196d42e26c01a69a4c", + "sha256:80ecf2451596f19fd607bb09953f426588fc1e79e93f5968ecf3367550396b22", + "sha256:8b49f1a3d1ee4cdaf5b32d2e738362c7f5e40ac8b46dd7d1a65e82a4872728fe", + "sha256:8e7da17f53e25d1a3bde5da4601e026adc9e8071f9f6f936d0fe3fe84ace6d54", + "sha256:a102424e28c6b47c67923a1f337ede4a4c2bba3965b01cf707978a801fc7442c", + "sha256:a19a6cc9c6ce4b1e7e3d319a473cf0ee989cbbe2b39201d7c19e214d2dfb80c7", + "sha256:a71a5b541078d0ebe373a81a3b7e71432c61d12e660f1d67896ca62d9628045b", + "sha256:baf95683cde5bc7d0e12d8e7588a3eb754d7c4fa714548adcd96bdf90169f021", + "sha256:cab15ff4832580aa440dc9790b8a6128abd0b88b7ee4dd56abacbc52f212209d", + "sha256:ce290e62229964715f1011c3dbeab7a4a1e4971fd6f31324c4519464473ef9f2", + "sha256:d3a8ffec2a50d8ec470143ea3d15c0c52d73df882eef92de7537e8ce13475e8a", + "sha256:e204937f67b28d2dca73ca936d3039a144a081fc47a07598d44854ea2a106239", + "sha256:eb23f58a446a7f09db85eda09521a498e109f137b85fb278edb2e34841055398", + "sha256:f6dd02ec01f4468da0f234da9d9c8545c5412fef80bc590cc51d8dd084138a89" + ], + "markers": "python_version >= '3.8'", + "version": "==7.2" } } } diff --git a/src/bench/Dockerfile b/src/bench/Dockerfile new file mode 100644 index 00000000..b22bc0b4 --- /dev/null +++ b/src/bench/Dockerfile @@ -0,0 +1,5 @@ +FROM locustio/locust:2.32.2 + +RUN pip install \ + pandas \ + pyarrow diff --git a/src/bench/README.md b/src/bench/README.md new file mode 100644 index 00000000..e69de29b diff --git a/src/bench/cli.py b/src/bench/cli.py new file mode 100644 index 00000000..107b56a2 --- /dev/null +++ b/src/bench/cli.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python + +"""Locust benchmark utility. + +This client provides utilities to modify Locust output files. +""" + +from pathlib import Path + +import pandas as pd +import typer + +import qualicharge + +app = typer.Typer(no_args_is_help=True) + + +@app.command() +def stamp(csv_file: Path, revision: str): + """Add date and version to locust stats csv file. + + It prints stamped CSV file in the standard output stream. + """ + df = pd.read_csv(csv_file, dtype_backend="pyarrow") + + # Add metadata + df["git"] = revision + df["timestamp"] = pd.Timestamp.now(tz="utc") + df["version"] = qualicharge.__version__ + typer.echo(df.to_csv(index=False)) + + +@app.command() +def diff(database: Path, current: Path, short: bool = True): + """Compare current bench with the last-known bench. + + Database path should point to the CSV file history, and current to the + ran benchmark. + """ + db = pd.read_csv(database, dtype_backend="pyarrow") + bench = pd.read_csv(current, dtype_backend="pyarrow") + + # Get latest revision + latest_revision = ( + db[["git", "timestamp"]].sort_values(by="timestamp").tail(1)["git"].iloc[0] + ) + latest = db.loc[db["git"] == latest_revision] + + # Calculate diff + cols = list( + set(latest.columns.values) - {"Type", "Name", "git", "timestamp", "version"} + ) + diff = bench[cols] - latest[cols] + diff.insert(0, "Type", latest["Type"]) + diff.insert(1, "Name", latest["Name"]) + + # Print result + short_columns = [ + "Type", + "Name", + "Request Count", + "Failure Count", + "Median Response Time", + "Average Response Time", + "Min Response Time", + "Max Response Time", + "Average Content Size", + "Requests/s", + ] + if short: + typer.echo(diff[short_columns].to_csv(index=False)) + else: + typer.echo(diff.to_csv(index=False)) + + +if __name__ == "__main__": + app() diff --git a/src/bench/locustfile.py b/src/bench/locustfile.py new file mode 100644 index 00000000..5ba20ca9 --- /dev/null +++ b/src/bench/locustfile.py @@ -0,0 +1,222 @@ +"""QualiCharge API load tests.""" + +import os +from datetime import datetime, timedelta, timezone +from functools import cache +from http import HTTPStatus +from pathlib import Path + +import pandas as pd +import requests +from locust import FastHttpUser, task + +API_ADMIN_USER: str = os.environ["QUALICHARGE_API_ADMIN_USER"] +API_ADMIN_PASSWORD: str = os.environ["QUALICHARGE_API_ADMIN_PASSWORD"] +STATIQUE_DATA_PATH: Path = Path(os.environ["QUALICHARGE_STATIQUE_DATA_PATH"]) +STATIC_DB_OFFSET: int = 500 + + +@cache +def load_statique_db(db_path: Path): + """Load statique database.""" + db = pd.read_json(db_path, dtype_backend="pyarrow", lines=True) + return db.to_dict(orient="records") + + +class BaseAPIUser(FastHttpUser): + """Base API user.""" + + abstract: bool = True + username: str + password: str + static_db_path: Path + counter: dict = { + "static": {"create": STATIC_DB_OFFSET, "bulk": 10000}, + } + + def on_start(self): + """Log user in on start.""" + credentials = { + "username": self.username, + "password": self.password, + } + response = requests.post( + f"{self.host}/auth/token", data=credentials, timeout=30 + ) + token = response.json()["access_token"] + self.client.auth_header = f"Bearer {token}" + self.statique_db = load_statique_db(self.static_db_path) + + @task + def whoami(self): + """Test the /whoami endpoint.""" + self.client.get("/auth/whoami") + + @task + def statique_list(self): + """Assess the /statique GET endpoint.""" + with self.rest("GET", "/statique/?limit=100") as response: + if response.js["size"] == 0: + response.failure("Database contains no statique entries") + with self.rest("GET", "/statique/?limit=10") as response: + if response.js["size"] == 0: + response.failure("Database contains no statique entries") + + @task + def statique_get(self): + """Assess the /statique/{id_pdc_itinerance} GET endpoint.""" + id_pdc_itinerance = "FRALLEGO002006P3" + with self.rest("GET", f"/statique/{id_pdc_itinerance}") as response: + if "id_pdc_itinerance" not in response.js: + response.failure( + "Database does not contain target statique entry " + f"{id_pdc_itinerance}" + ) + + @task + def statique_update(self): + """Assess the /statique/{id_pdc_itinerance} PUT endpoint.""" + data = self.statique_db[22] + data["date_maj"] = "2024-11-21" + id_pdc_itinerance = data["id_pdc_itinerance"] + + with self.rest("PUT", f"/statique/{id_pdc_itinerance}", json=data) as response: + if "id_pdc_itinerance" not in response.js: + response.failure( + "Database does not contain target statique entry" + f"{id_pdc_itinerance}" + ) + + @task + def statique_create(self): + """Assess the /statique/ POST endpoint.""" + index = self.counter["static"]["create"] + data = self.statique_db[index] + + with self.rest("POST", "/statique/", json=data) as response: + if response.status_code == HTTPStatus.OK and response.js["size"] == 0: + response.failure("No Statique entry was created") + self.counter["static"]["create"] += 1 + + @task + def statique_bulk(self): + """Assess the /statique/bulk POST endpoint.""" + start = self.counter["static"]["bulk"] + limit = 50 + end = start + limit + data = self.statique_db[start:end] + + with self.rest("POST", "/statique/bulk", json=data) as response: + if response.js["size"] == 0: + response.failure("No Statique entry was created") + self.counter["static"]["bulk"] = end + + @task + def status_list(self): + """Assess the /dynamique/status/ GET endpoint.""" + with self.rest("GET", "/dynamique/status/") as response: + if response.status_code == HTTPStatus.NOT_FOUND: + response.success() + + @task + def status_get(self): + """Assess the /dynamique/status/{id_pdc_itinerance} GET endpoint.""" + id_pdc_itinerance = "FRALLEGO002006P3" + with self.rest("GET", f"/dynamique/status/{id_pdc_itinerance}") as response: + if response.status_code == HTTPStatus.NOT_FOUND: + response.success() + + @task + def status_history(self): + """Assess the /dynamique/status/{id_pdc_itinerance}/history GET endpoint.""" + id_pdc_itinerance = "FRALLEGO002006P3" + with self.rest( + "GET", f"/dynamique/status/{id_pdc_itinerance}/history" + ) as response: + if response.status_code == HTTPStatus.NOT_FOUND: + response.success() + + @task + def status_create(self): + """Assess the /dynamique/status/ POST endpoint.""" + now = datetime.now(timezone.utc) + data = { + "etat_pdc": "en_service", + "occupation_pdc": "libre", + "horodatage": now.isoformat(), + "etat_prise_type_2": "fonctionnel", + "etat_prise_type_combo_ccs": "fonctionnel", + "etat_prise_type_chademo": "fonctionnel", + "etat_prise_type_ef": "fonctionnel", + "id_pdc_itinerance": "FRALLEGO002006P3", + } + with self.rest("POST", "/dynamique/status/", json=data) as _: + pass + + @task + def status_bulk(self): + """Assess the /dynamique/status/bulk POST endpoint.""" + now = datetime.now(timezone.utc) + base = { + "etat_pdc": "en_service", + "occupation_pdc": "libre", + "horodatage": now.isoformat(), + "etat_prise_type_2": "fonctionnel", + "etat_prise_type_combo_ccs": "fonctionnel", + "etat_prise_type_chademo": "fonctionnel", + "etat_prise_type_ef": "fonctionnel", + "id_pdc_itinerance": "FRALLEGO002006P3", + } + delta = timedelta(seconds=3) + size = 10 + data = [ + dict(base, horodatage=(now - delta * n).isoformat()) for n in range(size) + ] + + with self.rest("POST", "/dynamique/status/bulk", json=data) as _: + pass + + @task + def session_create(self): + """Assess the /dynamique/session/ POST endpoint.""" + now = datetime.now(timezone.utc) + data = { + "start": (now - timedelta(hours=1)).isoformat(), + "end": (now - timedelta(minutes=1)).isoformat(), + "energy": 666.66, + "id_pdc_itinerance": "FRALLEGO002006P3", + } + with self.rest("POST", "/dynamique/session/", json=data) as _: + pass + + @task + def session_bulk(self): + """Assess the /dynamique/session/bulk POST endpoint.""" + now = datetime.now(timezone.utc) + base = { + "start": (now - timedelta(hours=1)).isoformat(), + "end": (now - timedelta(minutes=1)).isoformat(), + "energy": 666.66, + "id_pdc_itinerance": "FRALLEGO002006P3", + } + size = 10 + data = [ + dict( + base, + start=(now - timedelta(hours=n, minutes=30)).isoformat(), + end=(now - timedelta(hours=n)).isoformat(), + energy=666.66 * (n + 1), + ) + for n in range(size) + ] + + with self.rest("POST", "/dynamique/session/bulk", json=data) as _: + pass + + +class APIAdminUser(BaseAPIUser): + """API admin user.""" + + username: str = API_ADMIN_USER + password: str = API_ADMIN_PASSWORD + static_db_path: Path = STATIQUE_DATA_PATH