diff --git a/.github/workflows/backend_test.yml b/.github/workflows/backend_test.yml index 3be87b4bb..2f79256ab 100644 --- a/.github/workflows/backend_test.yml +++ b/.github/workflows/backend_test.yml @@ -17,18 +17,18 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.10"] + python-version: ["3.12"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install Poetry run: pip install poetry - name: Install dependencies - working-directory: backend/src - run: poetry install + working-directory: backend + run: poetry install --with dev,docs - name: Start MySQL run: | sudo systemctl enable mysql.service @@ -48,6 +48,32 @@ jobs: KWAI_EMAIL_PASSWORD: ${{ secrets.KWAI_EMAIL_PASSWORD }} run: | cat < .kwai.toml + [frontend] + test = true + path = "" + root_app = "portal" + [frontend.apps.portal] + base="/apps/portal" + base_dev="http://localhost:3000" + entries="/src/index.ts" + [frontend.apps.author] + base="/apps/author" + base_dev="http://localhost:3001" + entries="/src/index.ts" + [frontend.apps.auth] + base="/apps/auth" + base_dev="http://localhost:3002" + entries="/src/index.ts" + [frontend.apps.coach] + base="/apps/coach" + base_dev="http://localhost:3003" + entries="/src/index.ts" + [frontend.apps.club] + base="/apps/club" + base_dev="http://localhost:3004" + entries="/src/index.ts" + [files] + path = "/var/tmp/kwai" [security] jwt_secret="$KWAI_JWT_SECRET" jwt_refresh_secret="$KWAI_JWT_SECRET" @@ -87,18 +113,18 @@ jobs: DBMATE_WAIT_TIMEOUT: "30s" run: ./dbmate up - name: Test with pytest - working-directory: backend/src + working-directory: backend env: KWAI_SETTINGS_FILE: ${{github.workspace}}/.kwai.toml run: poetry run pytest --cov=kwai --cov-report html - name: Generate coverage badge - working-directory: backend/src + working-directory: backend run: poetry run coverage-badge -o ./htmlcov/coverage.svg - name: Remove .gitignore from coverage report - run: rm backend/src/htmlcov/.gitignore + run: rm backend/htmlcov/.gitignore - name: Deploy coverage to github pages uses: JamesIves/github-pages-deploy-action@4.1.0 with: branch: gh-pages target-folder: coverage - folder: backend/src/htmlcov + folder: backend/htmlcov diff --git a/.github/workflows/generate_docs.yml b/.github/workflows/generate_docs.yml index af0859b8c..4624c0764 100644 --- a/.github/workflows/generate_docs.yml +++ b/.github/workflows/generate_docs.yml @@ -10,21 +10,21 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@master + uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-python@v3 + - uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.12" - name: Install Poetry run: pip install poetry - name: install - working-directory: backend/src - run: poetry install + working-directory: backend + run: poetry install --with docs - name: Build documentation - working-directory: backend/src + working-directory: backend run: | - poetry run mkdocs build -f ../../mkdocs.yml + poetry run mkdocs build -f ../mkdocs.yml - name: Copy site run: | mkdir -p gh-pages diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml new file mode 100644 index 000000000..c71f2e144 --- /dev/null +++ b/.github/workflows/mirror.yml @@ -0,0 +1,27 @@ +name: Mirror to Codeberg + +on: + push: + branches: ["**"] + tags: ["**"] + release: + types: ["published"] + workflow_dispatch: + +jobs: + mirror: + runs-on: ubuntu-latest + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: "Mirror to codeberg" + uses: cssnr/mirror-repository-action@master + with: + host: https://codeberg.org + owner: zumuta + repo: kwai + username: ${{ secrets.CODEBERG_USER }} + password: ${{ secrets.CODEBERG_TOKEN }} diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index 913950c7a..344ac11bd 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -10,8 +10,8 @@ jobs: ruff: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: chartboost/ruff-action@v1 + - uses: actions/checkout@v4 + - uses: astral-sh/ruff-action@v1 with: src: "${{ github.workspace }}/backend/src" - args: --ignore D102 + args: check --ignore D102 diff --git a/.gitignore b/.gitignore index 757d13472..b51cc0fa0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ /_site/ /backend/src/.venv/ /backend/src/.coverage -.turbo dist node_modules public @@ -24,3 +23,8 @@ __pycache__ /frontend/apps/portal/images/*.jpg *.tsbuildinfo stats.html +/backend/.venv/ +/frontend/packages/kwai-config/src/config.production.toml +.task +/frontend/.env.test +/backend/db/schema.sql diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 52df109fa..8e35a0967 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,11 +22,11 @@ repos: language_version: python3.12 - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.3.2 + rev: v0.7.3 hooks: - id: ruff types: [python] - args: [--ignore=D102] + args: [--ignore=D102, --fix] - repo: https://github.com/gitleaks/gitleaks rev: v8.18.2 hooks: diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 000000000..47b9c3696 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,20 @@ +version: '3' + +tasks: + # build documentation + build_doc: + desc: Build the documentation + dir: backend + cmds: + - poetry run mkdocs build -f ../mkdocs.yml + + serve_doc: + desc: Build the documentation and run the webserver + dir: backend + cmds: + - poetry run mkdocs serve -f ../mkdocs.yml + +includes: + frontend: + taskfile: ./frontend/Taskfile.yml + dir: ./frontend diff --git a/backend/docs/api/api_auth.md b/backend/docs/api/api_auth.md index 0c44c90bb..1b109081a 100644 --- a/backend/docs/api/api_auth.md +++ b/backend/docs/api/api_auth.md @@ -1,14 +1,57 @@ # Auth API's -## ::: kwai.api.v1.auth.endpoints.login - selection: - members: no -### ::: kwai.api.v1.auth.endpoints.login.login -### ::: kwai.api.v1.auth.endpoints.login.logout -### ::: kwai.api.v1.auth.endpoints.login.recover_user -### ::: kwai.api.v1.auth.endpoints.login.renew_access_token -### ::: kwai.api.v1.auth.endpoints.login.reset_password +All API's used for authentication, authorization, users, ... -# Auth Responses +## /api/v1/auth -### ::: kwai.api.v1.auth.endpoints.login.TokenSchema +### Requests + +::: kwai.api.v1.auth.endpoints.login.renew_access_token + options: + heading_level: 4 + +::: kwai.api.v1.auth.endpoints.login.login + options: + heading_level: 4 + +::: kwai.api.v1.auth.endpoints.login.logout + options: + heading_level: 4 + +::: kwai.api.v1.auth.endpoints.login.recover_user + options: + heading_level: 4 + +::: kwai.api.v1.auth.endpoints.login.reset_password + options: + heading_level: 4 + +::: kwai.api.v1.auth.endpoints.user.get + options: + heading_level: 4 + +### Responses + +#### ::: kwai.api.v1.auth.endpoints.login.TokenSchema + options: + show_root_toc_entry: false + +## /api/v1/auth/users + +### Requests + +::: kwai.api.v1.auth.endpoints.user_invitations.create_user_invitation + options: + heading_level: 4 + +::: kwai.api.v1.auth.endpoints.user_invitations.delete_user_invitation + options: + heading_level: 4 + +::: kwai.api.v1.auth.endpoints.user_invitations.get_user_invitations + options: + heading_level: 4 + +::: kwai.api.v1.auth.endpoints.user_invitations.get_user_invitation + options: + heading_level: 4 diff --git a/backend/docs/api/index.md b/backend/docs/api/index.md new file mode 100644 index 000000000..88ad15bf9 --- /dev/null +++ b/backend/docs/api/index.md @@ -0,0 +1,13 @@ +# API + +## [Authentication](./api_auth.md) + +All API's related to authentication. + +!!! Note + + Use [swagger](https://swagger.io/) UI from [FastAPI](https://fastapi.tiangolo.com) to get a list of + all available api's. + + When the Kwai api backend is running in test mode, point your browser + to `http://localhost:/api/docs`. diff --git a/backend/docs/architecture.md b/backend/docs/architecture.md new file mode 100644 index 000000000..8b4dc28a9 --- /dev/null +++ b/backend/docs/architecture.md @@ -0,0 +1,60 @@ +Architecture +============ + +Kwai tries to follow the [clean architecture](http://cleancoder.com) principles. The [frontend]() is already a +separated layer. The backend code is using the domain driven design (DDD) for modeling the software. + +One of the rules of clean architecture is that when you don't own or control something, then keep it on the +outside of your design or wrap it. This means for example, that the domain code isn't allowed to contain FastAPI code +or database related code. The code for the API is on the outside because it's the entry point of a call to the system. +Presenters are used to transform domain objects into JSON:API documents. The repository pattern keeps the +database code on the outside. And interfaces are used to protect the inside from the outside. + +The [pendulum](https://pendulum.eustace.io/) library is used for processing dates and timestamps. Because kwai doesn't +own this code, the pendulum code is wrapped into value objects (Timestamp, Date, ...). If the pendulum package is +outdated, we only need to change these value objects. + +> This is also the reason why [Pydantic](https://docs.pydantic.dev/latest/) isn't used for entities or value objects. +> Pydantic is great for validation and serialization, but we don't want Pydantic to become a dependency of the kwai +> domain. + +Dependency injection containers are only used on the outside. There should not be any magic code in the domain. +So, dependency injection containers can only be used in the API entry code, the CLI entry code, ... From there on, +the dependency should be passed as an argument (and passing it down should be done using an interface). + +Actors +====== + +Who are the actors in our application? + +Visitor +------- + +A visitor is a person that visits our website. He/She does not have any permissions and is +not known in the system. + +Member +------ + +A member is a person that is a member of the club. + +Coach +----- + +A coach is a member of the club. A coach can create/view/update/delete trainings. A coach can also registers +participants for a training. When participants are registered, a training can't be deleted anymore. + +````mermaid +sequenceDiagram + actor Coach + Coach->>Trainings: View + Coach->>Trainings: Create + Coach->>Trainings: Update + Coach->>Trainings: Delete + Coach->>Trainings: Register participants +```` + +Admin +----- + +An administrator is a person that manages the website. diff --git a/backend/docs/cli.md b/backend/docs/cli.md index fbc2aece0..466b642d8 100644 --- a/backend/docs/cli.md +++ b/backend/docs/cli.md @@ -1,10 +1,10 @@ # Command Line Interface -A command line interface (CLI) is provided to help managing the kwai system. To run the cli, use the kwai_cli.py +A command line interface (CLI) is provided to help managing the kwai system. To run the cli, use the kwai_cli.py script: `kwai_cli.py --help` -::: kwai.cli.bus +::: kwai.cli.commands.bus options: show_root_full_path: False show_signature: False @@ -12,7 +12,7 @@ script: - show - test -::: kwai.cli.db +::: kwai.cli.commands.db options: show_root_full_path: False show_signature: False @@ -20,10 +20,9 @@ script: - show - test -::: kwai.cli.identity +::: kwai.cli.commands.identity options: show_root_full_path: False show_signature: False members: - create - diff --git a/backend/docs/deploy.md b/backend/docs/deploy.md index e1c1cc446..06b979f4d 100644 --- a/backend/docs/deploy.md +++ b/backend/docs/deploy.md @@ -2,30 +2,32 @@ This page will describe how you can deploy the backend of kwai. -## Step 1: Clone +## Step 1: Build First you need to get the latest version. The repository is a monorepo. This means the backend code and the frontend code are in the same repository. -We only need the backend here: +We only need the backend. Set up the [development environment](./index.md) for kwai +and build the wheel file. ````shell -git clone --no-checkout https://codeberg.org/zumuta/kwai.git -cd kwai -git sparse-checkout init --cone -git sparse-checkout set backend -git checkout +cd backend +poetry build ```` -> When sparse-checkout is not available, you can safely remove the frontend directory. +This command creates a dist folder where you find two files: a tar.gz with the source code and a .whl file +that can used to install kwai. +Transfer the .whl file to your host. ## Step 2: Python Environment -Kwai needs a Python environment. [Poetry](https://python-poetry.org/) is used as Python packaging and -dependency management tool. Make sure it is available. +Kwai needs a Python environment. It is recommended to create a separate environment for kwai. +Run the following command on your host: ````shell -cd backend/src -poetry install +mkdir backend +python3 -m venv .venv +source .venv/bin/activate +pip install kwai-x.x.x-py3-none-any.whl ```` ## Step 3: Configuration @@ -41,25 +43,67 @@ cp kwai.dist.toml .kwai.toml Use an editor to change the configuration. Set the environment variable `KWAI_SETTINGS_FILE` with the full path of this configuration file. -## Step 4: Migration +## Step 4: Templates + +kwai requires jinja2 templates. Copy the templates to a folder on the server +and update the `path` setting in the `template` section of the configuration file. + +## Step 5: Migration When there are database changes required, a migration must run before -starting the backend. +starting the backend. Copy the migrations folder to your server and use dbmate to upgrade. > [dbmate](https://github.com/amacneil/dbmate) is used for database migrations. Make sure it is available. ````shell -cd backend/migrations +cd /migrations dbmate -d . -u "" up ```` -## Step 4: Run +## Step 6: Frontend + +The frontend is also served by the FastAPI backend. + +To build the frontend you need [Node](https://nodejs.org/en). + +````shell +cd frontend +npm install +npm run build +```` + +!!! Note + You can also use [Task](https://taskfile.dev/) to build the frontend. Run the following + command from the kwai root folder: + `task frontend:build` -To start the application use the following command: +This will result in a folder `dist` in all the frontend applications. +FastAPI will be used to render the frontend. Add all applications to the `.kwai.toml` configuration file: + +````toml +[frontend] +path = "/home/kwai/frontend" +root_app = "portal" + +[frontend.apps] + +[frontend.apps.portal] +base="/apps/portal" +entries="/src/index.ts" +```` + +In this example there should be a `/home/kwai/frontend/apps/portal/dist` folder that contains the result of the +build command. + +## Step 7: Run + +To start the backend application use the following command: ````shell -cd backend/src -poetry run python -m kwai.api +cd backend + +source .venv/bin/activate +python -m kwai ```` This python script will start an uvicorn server. The host diff --git a/backend/docs/index.md b/backend/docs/index.md index 79beafc87..041dbfa10 100644 --- a/backend/docs/index.md +++ b/backend/docs/index.md @@ -5,11 +5,17 @@ [![coverage](./tests/coverage/coverage.svg)](./tests/coverage/index.html) -kwai API is the backend for the kwai sports club management system. +This is the backend for the KWAI sports club management system. This system +contains a [JSON:API](https://jsonapi.org/) REST API, a CLI and an event bus. -All server side code is written with Python using [FastAPI](https://fastapi.tiangolo.com/) as web framework. +All server side code is written with Python using [FastAPI](https://fastapi.tiangolo.com/) for the REST API +and [Typer](https://typer.tiangolo.com/) for the CLI. +Currently, the event bus is custom code and not in use yet. -## Install +!!! note + The frontend is also served by FastAPI. + +## Develop ### Prerequisites @@ -18,12 +24,12 @@ Clone the repository to your system. [Poetry](https://python-poetry.org/) is used as Python packaging and dependency management tool. Make sure it is available. -Use Poetry to install all the dependencies: Make `backend/src` the current directory +Use Poetry to install all the dependencies: Make `backend` the current directory and run: `poetry install` -This will only install the modules required to run kwai, for developing add `dev` and `docs` dependencies: +This will only install the modules required to run KWAI, for developing add `dev` and `docs` dependencies: `poetry install --with dev,docs` @@ -40,7 +46,7 @@ available from the internet. ### Database -kwai needs a database. Migration files are available in the folder migrations. +KWAI needs a database. Migration files are available in the folder migrations. [Dbmate](https://github.com/amacneil/dbmate) is used as migration tool. ```console @@ -76,7 +82,7 @@ Use `kwai.dist.yaml` file to create `kwai.yaml` in each machine folder. This fil > Don't add `kwai.yaml` to version control! -## Develop +### Tools The backend is written in Python. The following tools are used to develop kwai: + [Poetry](https://python-poetry.org/) for managing dependencies. @@ -87,39 +93,42 @@ The backend is written in Python. The following tools are used to develop kwai: There are pre-commit hooks defined for formatting and linting the code. Use Poetry to create the pre-commit hooks: +> Use the backend folder as working directory for the poetry commands. + ```` -poetry -C ./backend/src/pyproject.toml pre-commit install +poetry run pre-commit install ```` -### Testing -Use the development vagrant machine to run kwai while developing. Use the test machine to test all code before pushing -code to the remote repository. In a development environment, poetry and pytest can be used to run the tests. On the -test machine, a script `kwai_test.sh` is provided to run the tests. This script will also update the coverage -documentation. +There are several github actions defined: + ++ backend_test: will run all pytest test when code is pushed in backend/src. ++ generate_docs: will generate this documentation. ++ mirror: will copy the repository to codeberg. ++ ruff: will check the code. -## Project structure +### Project structure The kwai API code in the repository is located in the `backend` folder. -### docs +#### docs This folder contains all files for creating this documentation site. -### migrations +#### migrations This folder contains the database migrations. [Dbmate](https://github.com/amacneil/dbmate) is used as migration tool. -### src +#### src This folder contains the Python code. The system is written following DDD as software development philosophy. Clean code should be the result of following this philosophy. The folder `kwai` contains the program code, `tests` contains the [pytest](https://pytest.org) code for testing the program code. -### templates +#### templates This folder contains all templates used by kwai. -### vagrant +#### vagrant This folder contains two vagrant machines: one for development and one for testing. diff --git a/backend/kwai.dist.toml b/backend/kwai.dist.toml index caf0cb145..748a1a3b9 100644 --- a/backend/kwai.dist.toml +++ b/backend/kwai.dist.toml @@ -1,4 +1,36 @@ # Rename this file to kwai.toml and set the env KWAI_SETTINGS_FILE to the path of this file. +[frontend] +test = false +path = "" # Where are the frontend applications deployed? +root_app = "portal" # Which app should be used as default? + +[frontend.apps] + +[frontend.apps.portal] +server="http://localhost:3000" # Only necessary in test mode +base="/apps/portal" # Only necessary in test mode +entries="src/index.ts" + +[frontend.apps.author] +server="http://localhost:3001" # Only necessary in test mode +base="/apps/author" # Only necessary in test mode +entries="src/index.ts" + +[frontend.apps.auth] +server="http://localhost:3002" # Only necessary in test mode +base="/apps/auth" # Only necessary in test mode +entries="src/index.ts" + +[frontend.apps.coach] +server="http://localhost:3003" # Only necessary in test mode +base="/apps/coach" # Only necessary in test mode +entries="src/index.ts" + +[frontend.apps.club] +server="http://localhost:3004" # Only necessary in test mode +base="/apps/club" # Only necessary in test mode +entries="src/index.ts" + [files] path="/var/tmp/kwai" diff --git a/backend/migrations/20240525191900_upload_preview.sql b/backend/migrations/20240525191900_upload_preview.sql new file mode 100644 index 000000000..e7fa8796e --- /dev/null +++ b/backend/migrations/20240525191900_upload_preview.sql @@ -0,0 +1,5 @@ +-- migrate:up + +alter table imports add column preview tinyint(1) default 0 not null; + +-- migrate:down diff --git a/backend/migrations/20240601194900_member_id.sql b/backend/migrations/20240601194900_member_id.sql new file mode 100644 index 000000000..b34822dda --- /dev/null +++ b/backend/migrations/20240601194900_member_id.sql @@ -0,0 +1,6 @@ +-- migrate:up + +alter table coaches rename column person_id to member_id; +alter table team_members rename column person_id to member_id; + +-- migrate:down diff --git a/backend/migrations/db/schema.sql b/backend/migrations/db/schema.sql index 9e96d8987..86c6afaa8 100644 --- a/backend/migrations/db/schema.sql +++ b/backend/migrations/db/schema.sql @@ -41,7 +41,7 @@ CREATE TABLE `applications` ( /*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `coaches` ( `id` int unsigned NOT NULL AUTO_INCREMENT, - `person_id` int NOT NULL, + `member_id` int NOT NULL, `description` text, `diploma` varchar(255) DEFAULT NULL, `active` tinyint(1) NOT NULL DEFAULT '1', @@ -108,6 +108,7 @@ CREATE TABLE `imports` ( `user_id` int NOT NULL, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NULL DEFAULT NULL, + `preview` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; /*!40101 SET character_set_client = @saved_cs_client */; @@ -346,11 +347,11 @@ CREATE TABLE `team_categories` ( /*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `team_members` ( `team_id` int NOT NULL, - `person_id` int NOT NULL, + `member_id` int NOT NULL, `active` tinyint(1) NOT NULL DEFAULT '1', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NULL DEFAULT NULL, - PRIMARY KEY (`team_id`,`person_id`) + PRIMARY KEY (`team_id`,`member_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; /*!40101 SET character_set_client = @saved_cs_client */; @@ -554,7 +555,7 @@ CREATE TABLE `users` ( `uuid` varchar(255) NOT NULL, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NULL DEFAULT NULL, - `person_id` int DEFAULT NULL, + `member_id` int DEFAULT NULL, `revoked` tinyint(1) NOT NULL DEFAULT '0', `last_unsuccessful_login` datetime DEFAULT NULL, `admin` tinyint(1) NOT NULL DEFAULT '0', @@ -586,5 +587,7 @@ INSERT INTO `schema_migrations` (version) VALUES ('20230128205126'), ('20231110160912'), ('20240201192100'), - ('20240502185700'); + ('20240502185700'), + ('20240525191900'), + ('20240601194900'); UNLOCK TABLES; diff --git a/backend/mkdocs.yml b/backend/mkdocs.yml index 9c13b578d..303f34d4c 100644 --- a/backend/mkdocs.yml +++ b/backend/mkdocs.yml @@ -4,8 +4,8 @@ docs_dir: docs nav: - index.md - - API: - - auth: api/api_auth.md + - architecture.md + - api/index.md - cli.md - source.md - deploy.md diff --git a/backend/poetry.lock b/backend/poetry.lock new file mode 100644 index 000000000..937d3874f --- /dev/null +++ b/backend/poetry.lock @@ -0,0 +1,3221 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "aiohappyeyeballs" +version = "2.4.3" +description = "Happy Eyeballs for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572"}, + {file = "aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586"}, +] + +[[package]] +name = "aiohttp" +version = "3.11.7" +description = "Async http client/server framework (asyncio)" +optional = false +python-versions = ">=3.9" +files = [ + {file = "aiohttp-3.11.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8bedb1f6cb919af3b6353921c71281b1491f948ca64408871465d889b4ee1b66"}, + {file = "aiohttp-3.11.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f5022504adab881e2d801a88b748ea63f2a9d130e0b2c430824682a96f6534be"}, + {file = "aiohttp-3.11.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e22d1721c978a6494adc824e0916f9d187fa57baeda34b55140315fa2f740184"}, + {file = "aiohttp-3.11.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e993676c71288618eb07e20622572b1250d8713e7e00ab3aabae28cb70f3640d"}, + {file = "aiohttp-3.11.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e13a05db87d3b241c186d0936808d0e4e12decc267c617d54e9c643807e968b6"}, + {file = "aiohttp-3.11.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ba8d043fed7ffa117024d7ba66fdea011c0e7602327c6d73cacaea38abe4491"}, + {file = "aiohttp-3.11.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda3ed0a7869d2fa16aa41f9961ade73aa2c2e3b2fcb0a352524e7b744881889"}, + {file = "aiohttp-3.11.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43bfd25113c1e98aec6c70e26d5f4331efbf4aa9037ba9ad88f090853bf64d7f"}, + {file = "aiohttp-3.11.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3dd3e7e7c9ef3e7214f014f1ae260892286647b3cf7c7f1b644a568fd410f8ca"}, + {file = "aiohttp-3.11.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:78c657ece7a73b976905ab9ec8be9ef2df12ed8984c24598a1791c58ce3b4ce4"}, + {file = "aiohttp-3.11.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:db70a47987e34494b451a334605bee57a126fe8d290511349e86810b4be53b01"}, + {file = "aiohttp-3.11.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:9e67531370a3b07e49b280c1f8c2df67985c790ad2834d1b288a2f13cd341c5f"}, + {file = "aiohttp-3.11.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9202f184cc0582b1db15056f2225ab4c1e3dac4d9ade50dd0613ac3c46352ac2"}, + {file = "aiohttp-3.11.7-cp310-cp310-win32.whl", hash = "sha256:2257bdd5cf54a4039a4337162cd8048f05a724380a2283df34620f55d4e29341"}, + {file = "aiohttp-3.11.7-cp310-cp310-win_amd64.whl", hash = "sha256:b7215bf2b53bc6cb35808149980c2ae80a4ae4e273890ac85459c014d5aa60ac"}, + {file = "aiohttp-3.11.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cea52d11e02123f125f9055dfe0ccf1c3857225fb879e4a944fae12989e2aef2"}, + {file = "aiohttp-3.11.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3ce18f703b7298e7f7633efd6a90138d99a3f9a656cb52c1201e76cb5d79cf08"}, + {file = "aiohttp-3.11.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:670847ee6aeb3a569cd7cdfbe0c3bec1d44828bbfbe78c5d305f7f804870ef9e"}, + {file = "aiohttp-3.11.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dda726f89bfa5c465ba45b76515135a3ece0088dfa2da49b8bb278f3bdeea12"}, + {file = "aiohttp-3.11.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c25b74a811dba37c7ea6a14d99eb9402d89c8d739d50748a75f3cf994cf19c43"}, + {file = "aiohttp-3.11.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5522ee72f95661e79db691310290c4618b86dff2d9b90baedf343fd7a08bf79"}, + {file = "aiohttp-3.11.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fbf41a6bbc319a7816ae0f0177c265b62f2a59ad301a0e49b395746eb2a9884"}, + {file = "aiohttp-3.11.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:59ee1925b5a5efdf6c4e7be51deee93984d0ac14a6897bd521b498b9916f1544"}, + {file = "aiohttp-3.11.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:24054fce8c6d6f33a3e35d1c603ef1b91bbcba73e3f04a22b4f2f27dac59b347"}, + {file = "aiohttp-3.11.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:351849aca2c6f814575c1a485c01c17a4240413f960df1bf9f5deb0003c61a53"}, + {file = "aiohttp-3.11.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:12724f3a211fa243570e601f65a8831372caf1a149d2f1859f68479f07efec3d"}, + {file = "aiohttp-3.11.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7ea4490360b605804bea8173d2d086b6c379d6bb22ac434de605a9cbce006e7d"}, + {file = "aiohttp-3.11.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e0bf378db07df0a713a1e32381a1b277e62ad106d0dbe17b5479e76ec706d720"}, + {file = "aiohttp-3.11.7-cp311-cp311-win32.whl", hash = "sha256:cd8d62cab363dfe713067027a5adb4907515861f1e4ce63e7be810b83668b847"}, + {file = "aiohttp-3.11.7-cp311-cp311-win_amd64.whl", hash = "sha256:bf0e6cce113596377cadda4e3ac5fb89f095bd492226e46d91b4baef1dd16f60"}, + {file = "aiohttp-3.11.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4bb7493c3e3a36d3012b8564bd0e2783259ddd7ef3a81a74f0dbfa000fce48b7"}, + {file = "aiohttp-3.11.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e143b0ef9cb1a2b4f74f56d4fbe50caa7c2bb93390aff52f9398d21d89bc73ea"}, + {file = "aiohttp-3.11.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f7c58a240260822dc07f6ae32a0293dd5bccd618bb2d0f36d51c5dbd526f89c0"}, + {file = "aiohttp-3.11.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d20cfe63a1c135d26bde8c1d0ea46fd1200884afbc523466d2f1cf517d1fe33"}, + {file = "aiohttp-3.11.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12e4d45847a174f77b2b9919719203769f220058f642b08504cf8b1cf185dacf"}, + {file = "aiohttp-3.11.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf4efa2d01f697a7dbd0509891a286a4af0d86902fc594e20e3b1712c28c0106"}, + {file = "aiohttp-3.11.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee6a4cdcbf54b8083dc9723cdf5f41f722c00db40ccf9ec2616e27869151129"}, + {file = "aiohttp-3.11.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c6095aaf852c34f42e1bd0cf0dc32d1e4b48a90bfb5054abdbb9d64b36acadcb"}, + {file = "aiohttp-3.11.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1cf03d27885f8c5ebf3993a220cc84fc66375e1e6e812731f51aab2b2748f4a6"}, + {file = "aiohttp-3.11.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1a17f6a230f81eb53282503823f59d61dff14fb2a93847bf0399dc8e87817307"}, + {file = "aiohttp-3.11.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:481f10a1a45c5f4c4a578bbd74cff22eb64460a6549819242a87a80788461fba"}, + {file = "aiohttp-3.11.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:db37248535d1ae40735d15bdf26ad43be19e3d93ab3f3dad8507eb0f85bb8124"}, + {file = "aiohttp-3.11.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9d18a8b44ec8502a7fde91446cd9c9b95ce7c49f1eacc1fb2358b8907d4369fd"}, + {file = "aiohttp-3.11.7-cp312-cp312-win32.whl", hash = "sha256:3d1c9c15d3999107cbb9b2d76ca6172e6710a12fda22434ee8bd3f432b7b17e8"}, + {file = "aiohttp-3.11.7-cp312-cp312-win_amd64.whl", hash = "sha256:018f1b04883a12e77e7fc161934c0f298865d3a484aea536a6a2ca8d909f0ba0"}, + {file = "aiohttp-3.11.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:241a6ca732d2766836d62c58c49ca7a93d08251daef0c1e3c850df1d1ca0cbc4"}, + {file = "aiohttp-3.11.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:aa3705a8d14de39898da0fbad920b2a37b7547c3afd2a18b9b81f0223b7d0f68"}, + {file = "aiohttp-3.11.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9acfc7f652b31853eed3b92095b0acf06fd5597eeea42e939bd23a17137679d5"}, + {file = "aiohttp-3.11.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcefcf2915a2dbdbce37e2fc1622129a1918abfe3d06721ce9f6cdac9b6d2eaa"}, + {file = "aiohttp-3.11.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c1f6490dd1862af5aae6cfcf2a274bffa9a5b32a8f5acb519a7ecf5a99a88866"}, + {file = "aiohttp-3.11.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac5462582d6561c1c1708853a9faf612ff4e5ea5e679e99be36143d6eabd8e"}, + {file = "aiohttp-3.11.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1a6309005acc4b2bcc577ba3b9169fea52638709ffacbd071f3503264620da"}, + {file = "aiohttp-3.11.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5b973cce96793725ef63eb449adfb74f99c043c718acb76e0d2a447ae369962"}, + {file = "aiohttp-3.11.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ce91a24aac80de6be8512fb1c4838a9881aa713f44f4e91dd7bb3b34061b497d"}, + {file = "aiohttp-3.11.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:875f7100ce0e74af51d4139495eec4025affa1a605280f23990b6434b81df1bd"}, + {file = "aiohttp-3.11.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c171fc35d3174bbf4787381716564042a4cbc008824d8195eede3d9b938e29a8"}, + {file = "aiohttp-3.11.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ee9afa1b0d2293c46954f47f33e150798ad68b78925e3710044e0d67a9487791"}, + {file = "aiohttp-3.11.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8360c7cc620abb320e1b8d603c39095101391a82b1d0be05fb2225471c9c5c52"}, + {file = "aiohttp-3.11.7-cp313-cp313-win32.whl", hash = "sha256:7a9318da4b4ada9a67c1dd84d1c0834123081e746bee311a16bb449f363d965e"}, + {file = "aiohttp-3.11.7-cp313-cp313-win_amd64.whl", hash = "sha256:fc6da202068e0a268e298d7cd09b6e9f3997736cd9b060e2750963754552a0a9"}, + {file = "aiohttp-3.11.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:17829f37c0d31d89aa6b8b010475a10233774771f9b6dc2cc352ea4f8ce95d9a"}, + {file = "aiohttp-3.11.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d6177077a31b1aecfc3c9070bd2f11419dbb4a70f30f4c65b124714f525c2e48"}, + {file = "aiohttp-3.11.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:badda65ac99555791eed75e234afb94686ed2317670c68bff8a4498acdaee935"}, + {file = "aiohttp-3.11.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0de6466b9d742b4ee56fe1b2440706e225eb48c77c63152b1584864a236e7a50"}, + {file = "aiohttp-3.11.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04b0cc74d5a882c9dacaeeccc1444f0233212b6f5be8bc90833feef1e1ce14b9"}, + {file = "aiohttp-3.11.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c7af3e50e5903d21d7b935aceed901cc2475463bc16ddd5587653548661fdb"}, + {file = "aiohttp-3.11.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c63f898f683d1379b9be5afc3dd139e20b30b0b1e0bf69a3fc3681f364cf1629"}, + {file = "aiohttp-3.11.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdadc3f6a32d6eca45f9a900a254757fd7855dfb2d8f8dcf0e88f0fae3ff8eb1"}, + {file = "aiohttp-3.11.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d329300fb23e14ed1f8c6d688dfd867d1dcc3b1d7cd49b7f8c5b44e797ce0932"}, + {file = "aiohttp-3.11.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5578cf40440eafcb054cf859964bc120ab52ebe0e0562d2b898126d868749629"}, + {file = "aiohttp-3.11.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:7b2f8107a3c329789f3c00b2daad0e35f548d0a55cda6291579136622099a46e"}, + {file = "aiohttp-3.11.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:43dd89a6194f6ab02a3fe36b09e42e2df19c211fc2050ce37374d96f39604997"}, + {file = "aiohttp-3.11.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d2fa6fc7cc865d26ff42480ac9b52b8c9b7da30a10a6442a9cdf429de840e949"}, + {file = "aiohttp-3.11.7-cp39-cp39-win32.whl", hash = "sha256:a7d9a606355655617fee25dd7e54d3af50804d002f1fd3118dd6312d26692d70"}, + {file = "aiohttp-3.11.7-cp39-cp39-win_amd64.whl", hash = "sha256:53c921b58fdc6485d6b2603e0132bb01cd59b8f0620ffc0907f525e0ba071687"}, + {file = "aiohttp-3.11.7.tar.gz", hash = "sha256:01a8aca4af3da85cea5c90141d23f4b0eee3cbecfd33b029a45a80f28c66c668"}, +] + +[package.dependencies] +aiohappyeyeballs = ">=2.3.0" +aiosignal = ">=1.1.2" +attrs = ">=17.3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +propcache = ">=0.2.0" +yarl = ">=1.17.0,<2.0" + +[package.extras] +speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] + +[[package]] +name = "aiosignal" +version = "1.3.1" +description = "aiosignal: a list of registered asynchronous callbacks" +optional = false +python-versions = ">=3.7" +files = [ + {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, + {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "anyio" +version = "4.6.2.post1" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.9" +files = [ + {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, + {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, +] + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] +trio = ["trio (>=0.26.1)"] + +[[package]] +name = "async-lru" +version = "2.0.4" +description = "Simple LRU cache for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "async-lru-2.0.4.tar.gz", hash = "sha256:b8a59a5df60805ff63220b2a0c5b5393da5521b113cd5465a44eb037d81a5627"}, + {file = "async_lru-2.0.4-py3-none-any.whl", hash = "sha256:ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224"}, +] + +[[package]] +name = "asyncmy" +version = "0.2.9" +description = "A fast asyncio MySQL driver" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "asyncmy-0.2.9-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:d077eaee9a126f36bbe95e0412baa89e93172dd46193ef7bf7650a686e458e50"}, + {file = "asyncmy-0.2.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83cf951a44294626df43c5a85cf328297c3bac63f25ede216f9706514dabb322"}, + {file = "asyncmy-0.2.9-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:8a1d63c1bb8e3a09c90767199954fd423c48084a1f6c0d956217bc2e48d37d6d"}, + {file = "asyncmy-0.2.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ecad6826086e47596c6aa65dcbe221305f3d9232f0d4de11b8562ee2c55464a"}, + {file = "asyncmy-0.2.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a664d58f9ebe4132f6cb3128206392be8ad71ad6fb09a5f4a990b04ec142024"}, + {file = "asyncmy-0.2.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f2bbd7b75e2d751216f48c3b1b5092b812d70c2cd0053f8d2f50ec3f76a525a8"}, + {file = "asyncmy-0.2.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:55e3bc41aa0d4ab410fc3a1d0c31b9cdb6688cd3b0cae6f2ee49c2e7f42968be"}, + {file = "asyncmy-0.2.9-cp310-cp310-win32.whl", hash = "sha256:ea44eefc965c62bcfebf34e9ef00f6e807edf51046046767c56914243e0737e4"}, + {file = "asyncmy-0.2.9-cp310-cp310-win_amd64.whl", hash = "sha256:2b4a2a7cf0bd5051931756e765fefef3c9f9561550e0dd8b1e79308d048b710a"}, + {file = "asyncmy-0.2.9-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:e2b77f03a17a8db338d74311e38ca6dbd4ff9aacb07d2af6b9e0cac9cf1c7b87"}, + {file = "asyncmy-0.2.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c19f27b7ff0e297f2981335a85599ffe1c9a8a35c97230203321d5d6e9e4cb30"}, + {file = "asyncmy-0.2.9-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:bf18aef65ac98f5130ca588c55a83a56e74ae416cf0fe2c0757a2b597c4269d0"}, + {file = "asyncmy-0.2.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef02186cc02cb767ee5d5cf9ab002d5c7910a1a9f4c16a666867a9325c9ec5e"}, + {file = "asyncmy-0.2.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:696da0f71db0fe11e62fa58cd5a27d7c9d9a90699d13d82640755d0061da0624"}, + {file = "asyncmy-0.2.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:84d20745bb187ced05bd4072ae8b0bff4b4622efa23b79935519edb717174584"}, + {file = "asyncmy-0.2.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ea242364523f6205c4426435272bd57cbf593c20d5e5551efb28d44cfbd595c2"}, + {file = "asyncmy-0.2.9-cp311-cp311-win32.whl", hash = "sha256:47609d34e6b49fc5ad5bd2a2a593ca120e143e2a4f4206f27a543c5c598a18ca"}, + {file = "asyncmy-0.2.9-cp311-cp311-win_amd64.whl", hash = "sha256:0d56df7342f7b5467a9d09a854f0e5602c8da09afdad8181ba40b0434d66d8a4"}, + {file = "asyncmy-0.2.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63c2a98f225560f9a52d5bd0d2e58517639e209e5d996e9ab7470e661b39394d"}, + {file = "asyncmy-0.2.9-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:20ae3acc326b4b104949cc5e3a728a927e671f671c6f26266ad4a44f57ea9a5b"}, + {file = "asyncmy-0.2.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8171a64888453423a17ae507cd97d256541ea880b314bba16376ab9deffef6e8"}, + {file = "asyncmy-0.2.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c966de493928f26218e0bfaa284cfa609540e52841c423d7babf9ca97c9ff820"}, + {file = "asyncmy-0.2.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4321c4cb4c691689aa26a56354e3fa723d89dc2cac82751e8671b2a4e6441778"}, + {file = "asyncmy-0.2.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cd7cde6759dbbfcc467c2af4ef3d75de0b756dde39a3d176383d8c6d9f8a34f3"}, + {file = "asyncmy-0.2.9-cp37-cp37m-win32.whl", hash = "sha256:7678d3641d5a19f20e7e19220c83405fe8616a3b437efbc494f34ad186cedcf0"}, + {file = "asyncmy-0.2.9-cp37-cp37m-win_amd64.whl", hash = "sha256:e8f48d09adf3426e7a59066eaae3c7c84c318ec56cc2f20732d652056c7a3f62"}, + {file = "asyncmy-0.2.9-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:4c4f1dc0acbaac8c3f046215031bbf3ca3d2cd7716244365325496e4f6222b78"}, + {file = "asyncmy-0.2.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:901aac048e5342acc62e1f68f6dec5aa3ed272cb2b138dca38d1c74fc414285d"}, + {file = "asyncmy-0.2.9-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c2d4ad8817f99d9734912c2ff91c42e419031441f512b4aecd7e40a167908c1c"}, + {file = "asyncmy-0.2.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544d3736fd6682f0201a123e4f49335420b6abf6c245abe0487f5967021f1436"}, + {file = "asyncmy-0.2.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f0c606a55625146e189534cc39038540f7a8f2c680ea82845c1f4315a9ad2914"}, + {file = "asyncmy-0.2.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:625f96371d64769b94f7f7f699cfa5be56e669828aef3698cbf4f5bb0014ccb3"}, + {file = "asyncmy-0.2.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eeeb53fdd54eef54b9793a7a5c849c5f7a2fb2540a637f21585a996ef9dd8845"}, + {file = "asyncmy-0.2.9-cp38-cp38-win32.whl", hash = "sha256:2136b749ac489c25ab3aab4a81ae6e9dfb18fd0a5ebda96cd72788c5e4d46927"}, + {file = "asyncmy-0.2.9-cp38-cp38-win_amd64.whl", hash = "sha256:d08fb8722150a9c0645665cf777916335687bddb5f37a8e02af772e330be777b"}, + {file = "asyncmy-0.2.9-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:dbee276a9c8750b522aaad86315a6ed1ffbcb9145ce89070db77831c00dd2da1"}, + {file = "asyncmy-0.2.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8755248429f9bd3d7768c71494c9943fced18f9f526f768e96f5b9b3c727c84"}, + {file = "asyncmy-0.2.9-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:64bcd5110dca7a96cb411de85ab8f79fa867e864150939b8e76286a66eab28fc"}, + {file = "asyncmy-0.2.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a83e3895bed6d44aa334deb1c343d4ffc64b0def2215149f8df2e0e13499250"}, + {file = "asyncmy-0.2.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:beb3d0e434ce0bd9e609cf5341c3b82433ef544f89055d3792186e11fa2433d9"}, + {file = "asyncmy-0.2.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dc608ff331c5d1065e2d3566493d2d9e17f36e315bd5fad3c91c421eea306edb"}, + {file = "asyncmy-0.2.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:02caedc00035b2bd0be5555ef61d83ee9cb356ab488ac40072630ba224af02b0"}, + {file = "asyncmy-0.2.9-cp39-cp39-win32.whl", hash = "sha256:5b944d9cdf7ce25b396cd1e0c9319ba24c6583bde7a5dd31157614f3b9cc5b2f"}, + {file = "asyncmy-0.2.9-cp39-cp39-win_amd64.whl", hash = "sha256:3ceb59b9307b5eb893f4d473fcbc43ac0321ffb0436e0115b20cc2e0baa44eb5"}, + {file = "asyncmy-0.2.9-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9f1ca623517552a637900b90d65b5bafc9c67bebf96e3427eecb9359ffa24b1"}, + {file = "asyncmy-0.2.9-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:49622dc4ec69b5a4cbddb3695a1e9249b31092c6f19604abb664b43dcb509b6f"}, + {file = "asyncmy-0.2.9-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8412e825443ee876ef0d55ac4356b56173f5cb64ca8e4638974f8cf5c912a63"}, + {file = "asyncmy-0.2.9-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:4025db2a27b1d84d3c68b5d5aacecac17258b69f25ec8a8c350c5f666003a778"}, + {file = "asyncmy-0.2.9-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da7640f3357849b176364ed546908e28c8460701ddc0d23cc3fa7113ec52a076"}, + {file = "asyncmy-0.2.9-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:d2593717fa7a92a7d361444726292ce34edea76d5aa67d469b5efeee1c9b729e"}, + {file = "asyncmy-0.2.9-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9f22e13bd77277593b56de2e4b65c40c2e81b1a42c4845d062403c5c5bc52bc"}, + {file = "asyncmy-0.2.9-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a4aa17cc6ac0f7bc6b72e08d112566e69a36e2e1ebebad43d699757b7b4ff028"}, + {file = "asyncmy-0.2.9-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7e6f5205722e67c910510e294ad483bdafa7e29d5cf455d49ffa4b819e55fd8"}, + {file = "asyncmy-0.2.9-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:1021796f1910a0c2ab2d878f8f5d56f939ef0681f9c1fe925b78161cad2f8297"}, + {file = "asyncmy-0.2.9-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b1dd463bb054138bd1fd3fec9911eb618e92f54f61abb476658f863340394d1"}, + {file = "asyncmy-0.2.9-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ad06f3c02d455947e95087d29f7122411208f0eadaf8671772fe5bad97d9873a"}, + {file = "asyncmy-0.2.9.tar.gz", hash = "sha256:da188be013291d1f831d63cdd3614567f4c63bfdcde73631ddff8df00c56d614"}, +] + +[[package]] +name = "attrs" +version = "24.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, +] + +[package.extras] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] + +[[package]] +name = "babel" +version = "2.16.0" +description = "Internationalization utilities" +optional = false +python-versions = ">=3.8" +files = [ + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, +] + +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] + +[[package]] +name = "bcrypt" +version = "4.2.1" +description = "Modern password hashing for your software and your servers" +optional = false +python-versions = ">=3.7" +files = [ + {file = "bcrypt-4.2.1-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:1340411a0894b7d3ef562fb233e4b6ed58add185228650942bdc885362f32c17"}, + {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ee315739bc8387aa36ff127afc99120ee452924e0df517a8f3e4c0187a0f5f"}, + {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dbd0747208912b1e4ce730c6725cb56c07ac734b3629b60d4398f082ea718ad"}, + {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:aaa2e285be097050dba798d537b6efd9b698aa88eef52ec98d23dcd6d7cf6fea"}, + {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:76d3e352b32f4eeb34703370e370997065d28a561e4a18afe4fef07249cb4396"}, + {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:b7703ede632dc945ed1172d6f24e9f30f27b1b1a067f32f68bf169c5f08d0425"}, + {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:89df2aea2c43be1e1fa066df5f86c8ce822ab70a30e4c210968669565c0f4685"}, + {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:04e56e3fe8308a88b77e0afd20bec516f74aecf391cdd6e374f15cbed32783d6"}, + {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cfdf3d7530c790432046c40cda41dfee8c83e29482e6a604f8930b9930e94139"}, + {file = "bcrypt-4.2.1-cp37-abi3-win32.whl", hash = "sha256:adadd36274510a01f33e6dc08f5824b97c9580583bd4487c564fc4617b328005"}, + {file = "bcrypt-4.2.1-cp37-abi3-win_amd64.whl", hash = "sha256:8c458cd103e6c5d1d85cf600e546a639f234964d0228909d8f8dbeebff82d526"}, + {file = "bcrypt-4.2.1-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:8ad2f4528cbf0febe80e5a3a57d7a74e6635e41af1ea5675282a33d769fba413"}, + {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:909faa1027900f2252a9ca5dfebd25fc0ef1417943824783d1c8418dd7d6df4a"}, + {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cde78d385d5e93ece5479a0a87f73cd6fa26b171c786a884f955e165032b262c"}, + {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:533e7f3bcf2f07caee7ad98124fab7499cb3333ba2274f7a36cf1daee7409d99"}, + {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:687cf30e6681eeda39548a93ce9bfbb300e48b4d445a43db4298d2474d2a1e54"}, + {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:041fa0155c9004eb98a232d54da05c0b41d4b8e66b6fc3cb71b4b3f6144ba837"}, + {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f85b1ffa09240c89aa2e1ae9f3b1c687104f7b2b9d2098da4e923f1b7082d331"}, + {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c6f5fa3775966cca251848d4d5393ab016b3afed251163c1436fefdec3b02c84"}, + {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:807261df60a8b1ccd13e6599c779014a362ae4e795f5c59747f60208daddd96d"}, + {file = "bcrypt-4.2.1-cp39-abi3-win32.whl", hash = "sha256:b588af02b89d9fad33e5f98f7838bf590d6d692df7153647724a7f20c186f6bf"}, + {file = "bcrypt-4.2.1-cp39-abi3-win_amd64.whl", hash = "sha256:e84e0e6f8e40a242b11bce56c313edc2be121cec3e0ec2d76fce01f6af33c07c"}, + {file = "bcrypt-4.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:76132c176a6d9953cdc83c296aeaed65e1a708485fd55abf163e0d9f8f16ce0e"}, + {file = "bcrypt-4.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e158009a54c4c8bc91d5e0da80920d048f918c61a581f0a63e4e93bb556d362f"}, + {file = "bcrypt-4.2.1.tar.gz", hash = "sha256:6765386e3ab87f569b276988742039baab087b2cdb01e809d74e74503c2faafe"}, +] + +[package.extras] +tests = ["pytest (>=3.2.1,!=3.3.0)"] +typecheck = ["mypy"] + +[[package]] +name = "black" +version = "24.10.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.9" +files = [ + {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, + {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, + {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, + {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, + {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, + {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, + {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, + {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, + {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, + {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, + {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, +] + +[package.dependencies] +aiohttp = {version = ">=3.10", optional = true, markers = "extra == \"d\""} +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.10)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "certifi" +version = "2024.8.30" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, +] + +[[package]] +name = "cffi" +version = "1.17.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.0" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "7.6.7" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "coverage-7.6.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:108bb458827765d538abcbf8288599fee07d2743357bdd9b9dad456c287e121e"}, + {file = "coverage-7.6.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c973b2fe4dc445cb865ab369df7521df9c27bf40715c837a113edaa2aa9faf45"}, + {file = "coverage-7.6.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c6b24007c4bcd0b19fac25763a7cac5035c735ae017e9a349b927cfc88f31c1"}, + {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acbb8af78f8f91b3b51f58f288c0994ba63c646bc1a8a22ad072e4e7e0a49f1c"}, + {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad32a981bcdedb8d2ace03b05e4fd8dace8901eec64a532b00b15217d3677dd2"}, + {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:34d23e28ccb26236718a3a78ba72744212aa383141961dd6825f6595005c8b06"}, + {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e25bacb53a8c7325e34d45dddd2f2fbae0dbc230d0e2642e264a64e17322a777"}, + {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af05bbba896c4472a29408455fe31b3797b4d8648ed0a2ccac03e074a77e2314"}, + {file = "coverage-7.6.7-cp310-cp310-win32.whl", hash = "sha256:796c9b107d11d2d69e1849b2dfe41730134b526a49d3acb98ca02f4985eeff7a"}, + {file = "coverage-7.6.7-cp310-cp310-win_amd64.whl", hash = "sha256:987a8e3da7da4eed10a20491cf790589a8e5e07656b6dc22d3814c4d88faf163"}, + {file = "coverage-7.6.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e61b0e77ff4dddebb35a0e8bb5a68bf0f8b872407d8d9f0c726b65dfabe2469"}, + {file = "coverage-7.6.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a5407a75ca4abc20d6252efeb238377a71ce7bda849c26c7a9bece8680a5d99"}, + {file = "coverage-7.6.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df002e59f2d29e889c37abd0b9ee0d0e6e38c24f5f55d71ff0e09e3412a340ec"}, + {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673184b3156cba06154825f25af33baa2671ddae6343f23175764e65a8c4c30b"}, + {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e69ad502f1a2243f739f5bd60565d14a278be58be4c137d90799f2c263e7049a"}, + {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60dcf7605c50ea72a14490d0756daffef77a5be15ed1b9fea468b1c7bda1bc3b"}, + {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9c2eb378bebb2c8f65befcb5147877fc1c9fbc640fc0aad3add759b5df79d55d"}, + {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c0317288f032221d35fa4cbc35d9f4923ff0dfd176c79c9b356e8ef8ef2dff4"}, + {file = "coverage-7.6.7-cp311-cp311-win32.whl", hash = "sha256:951aade8297358f3618a6e0660dc74f6b52233c42089d28525749fc8267dccd2"}, + {file = "coverage-7.6.7-cp311-cp311-win_amd64.whl", hash = "sha256:5e444b8e88339a2a67ce07d41faabb1d60d1004820cee5a2c2b54e2d8e429a0f"}, + {file = "coverage-7.6.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f07ff574986bc3edb80e2c36391678a271d555f91fd1d332a1e0f4b5ea4b6ea9"}, + {file = "coverage-7.6.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:49ed5ee4109258973630c1f9d099c7e72c5c36605029f3a91fe9982c6076c82b"}, + {file = "coverage-7.6.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3e8796434a8106b3ac025fd15417315d7a58ee3e600ad4dbcfddc3f4b14342c"}, + {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3b925300484a3294d1c70f6b2b810d6526f2929de954e5b6be2bf8caa1f12c1"}, + {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c42ec2c522e3ddd683dec5cdce8e62817afb648caedad9da725001fa530d354"}, + {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0266b62cbea568bd5e93a4da364d05de422110cbed5056d69339bd5af5685433"}, + {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e5f2a0f161d126ccc7038f1f3029184dbdf8f018230af17ef6fd6a707a5b881f"}, + {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c132b5a22821f9b143f87446805e13580b67c670a548b96da945a8f6b4f2efbb"}, + {file = "coverage-7.6.7-cp312-cp312-win32.whl", hash = "sha256:7c07de0d2a110f02af30883cd7dddbe704887617d5c27cf373362667445a4c76"}, + {file = "coverage-7.6.7-cp312-cp312-win_amd64.whl", hash = "sha256:fd49c01e5057a451c30c9b892948976f5d38f2cbd04dc556a82743ba8e27ed8c"}, + {file = "coverage-7.6.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:46f21663e358beae6b368429ffadf14ed0a329996248a847a4322fb2e35d64d3"}, + {file = "coverage-7.6.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:40cca284c7c310d622a1677f105e8507441d1bb7c226f41978ba7c86979609ab"}, + {file = "coverage-7.6.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77256ad2345c29fe59ae861aa11cfc74579c88d4e8dbf121cbe46b8e32aec808"}, + {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87ea64b9fa52bf395272e54020537990a28078478167ade6c61da7ac04dc14bc"}, + {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d608a7808793e3615e54e9267519351c3ae204a6d85764d8337bd95993581a8"}, + {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdd94501d65adc5c24f8a1a0eda110452ba62b3f4aeaba01e021c1ed9cb8f34a"}, + {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82c809a62e953867cf57e0548c2b8464207f5f3a6ff0e1e961683e79b89f2c55"}, + {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb684694e99d0b791a43e9fc0fa58efc15ec357ac48d25b619f207c41f2fd384"}, + {file = "coverage-7.6.7-cp313-cp313-win32.whl", hash = "sha256:963e4a08cbb0af6623e61492c0ec4c0ec5c5cf74db5f6564f98248d27ee57d30"}, + {file = "coverage-7.6.7-cp313-cp313-win_amd64.whl", hash = "sha256:14045b8bfd5909196a90da145a37f9d335a5d988a83db34e80f41e965fb7cb42"}, + {file = "coverage-7.6.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f2c7a045eef561e9544359a0bf5784b44e55cefc7261a20e730baa9220c83413"}, + {file = "coverage-7.6.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dd4e4a49d9c72a38d18d641135d2fb0bdf7b726ca60a103836b3d00a1182acd"}, + {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c95e0fa3d1547cb6f021ab72f5c23402da2358beec0a8e6d19a368bd7b0fb37"}, + {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f63e21ed474edd23f7501f89b53280014436e383a14b9bd77a648366c81dce7b"}, + {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead9b9605c54d15be228687552916c89c9683c215370c4a44f1f217d2adcc34d"}, + {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0573f5cbf39114270842d01872952d301027d2d6e2d84013f30966313cadb529"}, + {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e2c8e3384c12dfa19fa9a52f23eb091a8fad93b5b81a41b14c17c78e23dd1d8b"}, + {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:70a56a2ec1869e6e9fa69ef6b76b1a8a7ef709972b9cc473f9ce9d26b5997ce3"}, + {file = "coverage-7.6.7-cp313-cp313t-win32.whl", hash = "sha256:dbba8210f5067398b2c4d96b4e64d8fb943644d5eb70be0d989067c8ca40c0f8"}, + {file = "coverage-7.6.7-cp313-cp313t-win_amd64.whl", hash = "sha256:dfd14bcae0c94004baba5184d1c935ae0d1231b8409eb6c103a5fd75e8ecdc56"}, + {file = "coverage-7.6.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37a15573f988b67f7348916077c6d8ad43adb75e478d0910957394df397d2874"}, + {file = "coverage-7.6.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b6cce5c76985f81da3769c52203ee94722cd5d5889731cd70d31fee939b74bf0"}, + {file = "coverage-7.6.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ab9763d291a17b527ac6fd11d1a9a9c358280adb320e9c2672a97af346ac2c"}, + {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cf96ceaa275f071f1bea3067f8fd43bec184a25a962c754024c973af871e1b7"}, + {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aee9cf6b0134d6f932d219ce253ef0e624f4fa588ee64830fcba193269e4daa3"}, + {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2bc3e45c16564cc72de09e37413262b9f99167803e5e48c6156bccdfb22c8327"}, + {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:623e6965dcf4e28a3debaa6fcf4b99ee06d27218f46d43befe4db1c70841551c"}, + {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:850cfd2d6fc26f8346f422920ac204e1d28814e32e3a58c19c91980fa74d8289"}, + {file = "coverage-7.6.7-cp39-cp39-win32.whl", hash = "sha256:c296263093f099da4f51b3dff1eff5d4959b527d4f2f419e16508c5da9e15e8c"}, + {file = "coverage-7.6.7-cp39-cp39-win_amd64.whl", hash = "sha256:90746521206c88bdb305a4bf3342b1b7316ab80f804d40c536fc7d329301ee13"}, + {file = "coverage-7.6.7-pp39.pp310-none-any.whl", hash = "sha256:0ddcb70b3a3a57581b450571b31cb774f23eb9519c2aaa6176d3a84c9fc57671"}, + {file = "coverage-7.6.7.tar.gz", hash = "sha256:d79d4826e41441c9a118ff045e4bccb9fdbdcb1d02413e7ea6eb5c87b5439d24"}, +] + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "coverage-badge" +version = "1.1.2" +description = "Generate coverage badges for Coverage.py." +optional = false +python-versions = "*" +files = [ + {file = "coverage_badge-1.1.2-py2.py3-none-any.whl", hash = "sha256:d8413ce51c91043a1692b943616b450868cbeeb0ea6a0c54a32f8318c9c96ff7"}, + {file = "coverage_badge-1.1.2.tar.gz", hash = "sha256:fe7ed58a3b72dad85a553b64a99e963dea3847dcd0b8ddd2b38a00333618642c"}, +] + +[package.dependencies] +coverage = "*" +setuptools = "*" + +[[package]] +name = "cryptography" +version = "42.0.8" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = ">=3.7" +files = [ + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"}, + {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"}, + {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"}, + {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"}, + {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"}, + {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"}, + {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"}, + {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"}, + {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"}, + {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"}, + {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"}, + {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"}, + {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"}, + {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"}, +] + +[package.dependencies] +cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] +docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] +nox = ["nox"] +pep8test = ["check-sdist", "click", "mypy", "ruff"] +sdist = ["build"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "deepdiff" +version = "6.7.1" +description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." +optional = false +python-versions = ">=3.7" +files = [ + {file = "deepdiff-6.7.1-py3-none-any.whl", hash = "sha256:58396bb7a863cbb4ed5193f548c56f18218060362311aa1dc36397b2f25108bd"}, + {file = "deepdiff-6.7.1.tar.gz", hash = "sha256:b367e6fa6caac1c9f500adc79ada1b5b1242c50d5f716a1a4362030197847d30"}, +] + +[package.dependencies] +ordered-set = ">=4.0.2,<4.2.0" + +[package.extras] +cli = ["click (==8.1.3)", "pyyaml (==6.0.1)"] +optimize = ["orjson"] + +[[package]] +name = "distlib" +version = "0.3.9" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, +] + +[[package]] +name = "dnspython" +version = "2.7.0" +description = "DNS toolkit" +optional = false +python-versions = ">=3.9" +files = [ + {file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"}, + {file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"}, +] + +[package.extras] +dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.16.0)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "quart-trio (>=0.11.0)", "sphinx (>=7.2.0)", "sphinx-rtd-theme (>=2.0.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] +dnssec = ["cryptography (>=43)"] +doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] +doq = ["aioquic (>=1.0.0)"] +idna = ["idna (>=3.7)"] +trio = ["trio (>=0.23)"] +wmi = ["wmi (>=1.5.1)"] + +[[package]] +name = "fastapi" +version = "0.110.3" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fastapi-0.110.3-py3-none-any.whl", hash = "sha256:fd7600612f755e4050beb74001310b5a7e1796d149c2ee363124abdfa0289d32"}, + {file = "fastapi-0.110.3.tar.gz", hash = "sha256:555700b0159379e94fdbfc6bb66a0f1c43f4cf7060f25239af3d84b63a656626"}, +] + +[package.dependencies] +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +starlette = ">=0.37.2,<0.38.0" +typing-extensions = ">=4.8.0" + +[package.extras] +all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] + +[[package]] +name = "filelock" +version = "3.16.1" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.8" +files = [ + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] +typing = ["typing-extensions (>=4.12.2)"] + +[[package]] +name = "frozenlist" +version = "1.5.0" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = false +python-versions = ">=3.8" +files = [ + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, + {file = "frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba"}, + {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab"}, + {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5"}, + {file = "frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb"}, + {file = "frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, + {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, + {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, + {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, + {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, + {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, + {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, + {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, + {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, + {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, + {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, + {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, + {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, + {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, + {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, + {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9"}, + {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf"}, + {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e"}, + {file = "frozenlist-1.5.0-cp38-cp38-win32.whl", hash = "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723"}, + {file = "frozenlist-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336"}, + {file = "frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08"}, + {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0"}, + {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c"}, + {file = "frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3"}, + {file = "frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0"}, + {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, + {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, +] + +[[package]] +name = "ghp-import" +version = "2.1.0" +description = "Copy your docs directly to the gh-pages branch." +optional = false +python-versions = "*" +files = [ + {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, + {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, +] + +[package.dependencies] +python-dateutil = ">=2.8.1" + +[package.extras] +dev = ["flake8", "markdown", "twine", "wheel"] + +[[package]] +name = "griffe" +version = "1.5.1" +description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." +optional = false +python-versions = ">=3.9" +files = [ + {file = "griffe-1.5.1-py3-none-any.whl", hash = "sha256:ad6a7980f8c424c9102160aafa3bcdf799df0e75f7829d75af9ee5aef656f860"}, + {file = "griffe-1.5.1.tar.gz", hash = "sha256:72964f93e08c553257706d6cd2c42d1c172213feb48b2be386f243380b405d4b"}, +] + +[package.dependencies] +colorama = ">=0.4" + +[[package]] +name = "griffe-fastapi" +version = "0.1.5" +description = "Griffe extension for FastAPI." +optional = false +python-versions = "<4.0,>=3.12" +files = [ + {file = "griffe_fastapi-0.1.5-py3-none-any.whl", hash = "sha256:d53b23d524c7ace0a1f85f477f7b58de995b0834bc440ccd851e758b825626c8"}, + {file = "griffe_fastapi-0.1.5.tar.gz", hash = "sha256:d1534dd0ad9f12e34d66cfce5d797b93129b4d3b174c79fcaeb3d2d1723c71d5"}, +] + +[package.dependencies] +griffe = ">=1.5.1,<2.0.0" + +[[package]] +name = "h11" +version = "0.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "httpcore" +version = "1.0.7" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, + {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httptools" +version = "0.6.4" +description = "A collection of framework independent HTTP protocol utils." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0"}, + {file = "httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da"}, + {file = "httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1"}, + {file = "httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50"}, + {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959"}, + {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4"}, + {file = "httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c"}, + {file = "httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069"}, + {file = "httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a"}, + {file = "httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975"}, + {file = "httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636"}, + {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721"}, + {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988"}, + {file = "httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17"}, + {file = "httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2"}, + {file = "httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44"}, + {file = "httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1"}, + {file = "httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2"}, + {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81"}, + {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f"}, + {file = "httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970"}, + {file = "httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660"}, + {file = "httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083"}, + {file = "httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3"}, + {file = "httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071"}, + {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5"}, + {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0"}, + {file = "httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8"}, + {file = "httptools-0.6.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d3f0d369e7ffbe59c4b6116a44d6a8eb4783aae027f2c0b366cf0aa964185dba"}, + {file = "httptools-0.6.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:94978a49b8f4569ad607cd4946b759d90b285e39c0d4640c6b36ca7a3ddf2efc"}, + {file = "httptools-0.6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40dc6a8e399e15ea525305a2ddba998b0af5caa2566bcd79dcbe8948181eeaff"}, + {file = "httptools-0.6.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab9ba8dcf59de5181f6be44a77458e45a578fc99c31510b8c65b7d5acc3cf490"}, + {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:fc411e1c0a7dcd2f902c7c48cf079947a7e65b5485dea9decb82b9105ca71a43"}, + {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:d54efd20338ac52ba31e7da78e4a72570cf729fac82bc31ff9199bedf1dc7440"}, + {file = "httptools-0.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:df959752a0c2748a65ab5387d08287abf6779ae9165916fe053e68ae1fbdc47f"}, + {file = "httptools-0.6.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:85797e37e8eeaa5439d33e556662cc370e474445d5fab24dcadc65a8ffb04003"}, + {file = "httptools-0.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:db353d22843cf1028f43c3651581e4bb49374d85692a85f95f7b9a130e1b2cab"}, + {file = "httptools-0.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1ffd262a73d7c28424252381a5b854c19d9de5f56f075445d33919a637e3547"}, + {file = "httptools-0.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:703c346571fa50d2e9856a37d7cd9435a25e7fd15e236c397bf224afaa355fe9"}, + {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aafe0f1918ed07b67c1e838f950b1c1fabc683030477e60b335649b8020e1076"}, + {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0e563e54979e97b6d13f1bbc05a96109923e76b901f786a5eae36e99c01237bd"}, + {file = "httptools-0.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:b799de31416ecc589ad79dd85a0b2657a8fe39327944998dea368c1d4c9e55e6"}, + {file = "httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c"}, +] + +[package.extras] +test = ["Cython (>=0.29.24)"] + +[[package]] +name = "httpx" +version = "0.26.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.26.0-py3-none-any.whl", hash = "sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd"}, + {file = "httpx-0.26.0.tar.gz", hash = "sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "identify" +version = "2.6.2" +description = "File identification library for Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "identify-2.6.2-py2.py3-none-any.whl", hash = "sha256:c097384259f49e372f4ea00a19719d95ae27dd5ff0fd77ad630aa891306b82f3"}, + {file = "identify-2.6.2.tar.gz", hash = "sha256:fab5c716c24d7a789775228823797296a2994b075fb6080ac83a102772a98cbd"}, +] + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "inject" +version = "5.2.1" +description = "Python dependency injection framework." +optional = false +python-versions = "*" +files = [ + {file = "inject-5.2.1-py2.py3-none-any.whl", hash = "sha256:e40a5b1bebd8a4050b6f98f3396f3de6e9e2e411ad2a2145f16f351cb6f54e51"}, + {file = "inject-5.2.1.tar.gz", hash = "sha256:f7c305a75cc4e3a331d248e996f25783ba784b88d5a9b9f73c53eacaa6d76985"}, +] + +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "loguru" +version = "0.7.2" +description = "Python logging made (stupidly) simple" +optional = false +python-versions = ">=3.5" +files = [ + {file = "loguru-0.7.2-py3-none-any.whl", hash = "sha256:003d71e3d3ed35f0f8984898359d65b79e5b21943f78af86aa5491210429b8eb"}, + {file = "loguru-0.7.2.tar.gz", hash = "sha256:e671a53522515f34fd406340ee968cb9ecafbc4b36c679da03c18fd8d0bd51ac"}, +] + +[package.dependencies] +colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} +win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} + +[package.extras] +dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptiongroup (==1.1.3)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.4.1)", "mypy (==v1.5.1)", "pre-commit (==3.4.0)", "pytest (==6.1.2)", "pytest (==7.4.0)", "pytest-cov (==2.12.1)", "pytest-cov (==4.1.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.0.0)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.3.0)", "tox (==3.27.1)", "tox (==4.11.0)"] + +[[package]] +name = "markdown" +version = "3.7" +description = "Python implementation of John Gruber's Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803"}, + {file = "markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2"}, +] + +[package.extras] +docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] +testing = ["coverage", "pyyaml"] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "markupsafe" +version = "3.0.2" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.9" +files = [ + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +description = "A deep merge function for 🐍." +optional = false +python-versions = ">=3.6" +files = [ + {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, + {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +description = "Project documentation with Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e"}, + {file = "mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2"}, +] + +[package.dependencies] +click = ">=7.0" +colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} +ghp-import = ">=1.0" +jinja2 = ">=2.11.1" +markdown = ">=3.3.6" +markupsafe = ">=2.0.1" +mergedeep = ">=1.3.4" +mkdocs-get-deps = ">=0.2.0" +packaging = ">=20.5" +pathspec = ">=0.11.1" +pyyaml = ">=5.1" +pyyaml-env-tag = ">=0.1" +watchdog = ">=2.0" + +[package.extras] +i18n = ["babel (>=2.9.0)"] +min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.4)", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"] + +[[package]] +name = "mkdocs-autorefs" +version = "1.2.0" +description = "Automatically link across pages in MkDocs." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_autorefs-1.2.0-py3-none-any.whl", hash = "sha256:d588754ae89bd0ced0c70c06f58566a4ee43471eeeee5202427da7de9ef85a2f"}, + {file = "mkdocs_autorefs-1.2.0.tar.gz", hash = "sha256:a86b93abff653521bda71cf3fc5596342b7a23982093915cb74273f67522190f"}, +] + +[package.dependencies] +Markdown = ">=3.3" +markupsafe = ">=2.0.1" +mkdocs = ">=1.1" + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"}, + {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"}, +] + +[package.dependencies] +mergedeep = ">=1.3.4" +platformdirs = ">=2.2.0" +pyyaml = ">=5.1" + +[[package]] +name = "mkdocs-material" +version = "9.5.45" +description = "Documentation that simply works" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_material-9.5.45-py3-none-any.whl", hash = "sha256:a9be237cfd0be14be75f40f1726d83aa3a81ce44808dc3594d47a7a592f44547"}, + {file = "mkdocs_material-9.5.45.tar.gz", hash = "sha256:286489cf0beca4a129d91d59d6417419c63bceed1ce5cd0ec1fc7e1ebffb8189"}, +] + +[package.dependencies] +babel = ">=2.10,<3.0" +colorama = ">=0.4,<1.0" +jinja2 = ">=3.0,<4.0" +markdown = ">=3.2,<4.0" +mkdocs = ">=1.6,<2.0" +mkdocs-material-extensions = ">=1.3,<2.0" +paginate = ">=0.5,<1.0" +pygments = ">=2.16,<3.0" +pymdown-extensions = ">=10.2,<11.0" +regex = ">=2022.4" +requests = ">=2.26,<3.0" + +[package.extras] +git = ["mkdocs-git-committers-plugin-2 (>=1.1,<2.0)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4,<2.0)"] +imaging = ["cairosvg (>=2.6,<3.0)", "pillow (>=10.2,<11.0)"] +recommended = ["mkdocs-minify-plugin (>=0.7,<1.0)", "mkdocs-redirects (>=1.2,<2.0)", "mkdocs-rss-plugin (>=1.6,<2.0)"] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +description = "Extension pack for Python Markdown and MkDocs Material." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, + {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, +] + +[[package]] +name = "mkdocs-monorepo-plugin" +version = "1.1.0" +description = "Plugin for adding monorepository support in Mkdocs." +optional = false +python-versions = ">=3" +files = [ + {file = "mkdocs-monorepo-plugin-1.1.0.tar.gz", hash = "sha256:ccc566e166aac5ae7fade498c15c4a337a4892d238629b51aba8ef3fc7099034"}, + {file = "mkdocs_monorepo_plugin-1.1.0-py3-none-any.whl", hash = "sha256:7bbfd9756a7fdecf64d6105dad96cce7e7bb5f0d6cfc2bfda31a1919c77cc3b9"}, +] + +[package.dependencies] +mkdocs = ">=1.0.4" +python-slugify = ">=4.0.1" + +[[package]] +name = "mkdocstrings" +version = "0.27.0" +description = "Automatic documentation from sources, for MkDocs." +optional = false +python-versions = ">=3.9" +files = [ + {file = "mkdocstrings-0.27.0-py3-none-any.whl", hash = "sha256:6ceaa7ea830770959b55a16203ac63da24badd71325b96af950e59fd37366332"}, + {file = "mkdocstrings-0.27.0.tar.gz", hash = "sha256:16adca6d6b0a1f9e0c07ff0b02ced8e16f228a9d65a37c063ec4c14d7b76a657"}, +] + +[package.dependencies] +click = ">=7.0" +Jinja2 = ">=2.11.1" +Markdown = ">=3.6" +MarkupSafe = ">=1.1" +mkdocs = ">=1.4" +mkdocs-autorefs = ">=1.2" +platformdirs = ">=2.2" +pymdown-extensions = ">=6.3" + +[package.extras] +crystal = ["mkdocstrings-crystal (>=0.3.4)"] +python = ["mkdocstrings-python (>=0.5.2)"] +python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] + +[[package]] +name = "mkdocstrings-python" +version = "1.12.2" +description = "A Python handler for mkdocstrings." +optional = false +python-versions = ">=3.9" +files = [ + {file = "mkdocstrings_python-1.12.2-py3-none-any.whl", hash = "sha256:7f7d40d6db3cb1f5d19dbcd80e3efe4d0ba32b073272c0c0de9de2e604eda62a"}, + {file = "mkdocstrings_python-1.12.2.tar.gz", hash = "sha256:7a1760941c0b52a2cd87b960a9e21112ffe52e7df9d0b9583d04d47ed2e186f3"}, +] + +[package.dependencies] +griffe = ">=0.49" +mkdocs-autorefs = ">=1.2" +mkdocstrings = ">=0.26" + +[[package]] +name = "multidict" +version = "6.1.0" +description = "multidict implementation" +optional = false +python-versions = ">=3.8" +files = [ + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, + {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, + {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, + {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, + {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, + {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, + {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, + {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, + {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, + {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, + {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, + {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, + {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, + {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, + {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, +] + +[[package]] +name = "mypy" +version = "1.13.0" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +typing-extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "mysql-connector-python" +version = "8.4.0" +description = "MySQL driver written in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mysql-connector-python-8.4.0.tar.gz", hash = "sha256:42542d131d63c78416d410fdc9e84b9acb960d715c2e7b28c57ac9577c6d8165"}, + {file = "mysql_connector_python-8.4.0-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:c0a2688d95d53cfbea9352ed61926b47bc9042570570fb8fe0a8d19b1e20f1c4"}, + {file = "mysql_connector_python-8.4.0-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:276bae0d5d44abb7ba1205003b55628e4e6f1d399f1825d518bc607320997b1f"}, + {file = "mysql_connector_python-8.4.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:a6d24ea29b3c2bdbba6861590de557665420bfb938f74b5cecc630bac5457d35"}, + {file = "mysql_connector_python-8.4.0-cp310-cp310-manylinux_2_17_x86_64.whl", hash = "sha256:b7876358d9e51f25edc492088c4ce16cd14c2db87c279a965b0f9c327723359c"}, + {file = "mysql_connector_python-8.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:085024bf12d15f9b428938fdbeb50bd9b15dda9c4d3a474e6df061cb08713e6a"}, + {file = "mysql_connector_python-8.4.0-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4e83fc8ed95005b171ffa36a289dac48625048263b09b56718e8395539ea07d9"}, + {file = "mysql_connector_python-8.4.0-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:cd89d1c8c2d1e33e5ac2d4eac5813422c150a8427fb60a16c59be18c29dd9a94"}, + {file = "mysql_connector_python-8.4.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:76c13fde35a038afe50550a9af7b31b28ca3a04cce06f3030980afb20460d28c"}, + {file = "mysql_connector_python-8.4.0-cp311-cp311-manylinux_2_17_x86_64.whl", hash = "sha256:accf10425c6af39a9595a47e7119ebcbcd7351f7df28755dbee01bca5a605b7c"}, + {file = "mysql_connector_python-8.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cda868bb4e1641362d148f5b0d2a86188cffa2f7188831589781b13f2df6f51a"}, + {file = "mysql_connector_python-8.4.0-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:3ae951f2e16d089975cb9f05b3f3e58807dc33a2e5a627047bba1c8ad5439d82"}, + {file = "mysql_connector_python-8.4.0-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:af40b5bdd91547d3dbf5fa62bde37e9e840bd7cba3b9246b55c09e6a1cde536f"}, + {file = "mysql_connector_python-8.4.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:bb4f3edab78f3fd6f80c6c0a9e5a533704044fc01bfb9e8736e1a993f74aa42d"}, + {file = "mysql_connector_python-8.4.0-cp312-cp312-manylinux_2_17_x86_64.whl", hash = "sha256:e549674c72b596a7386f4a76bbac2ee9581f6632e6713618a70468713b162964"}, + {file = "mysql_connector_python-8.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:aed505adc76b58282c76e6cbf3da195be0f84029a41f05c470be977481896074"}, + {file = "mysql_connector_python-8.4.0-cp38-cp38-macosx_13_0_x86_64.whl", hash = "sha256:d343a4a8133ae9561bd537fc8cdbcab74a0607a5f40698569010fa3c7d4a048f"}, + {file = "mysql_connector_python-8.4.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:74b1759d8bd9ccd4296dc2e5abe22ec7efbd1ad12a9032c2cb4d17fa5d0ca6e0"}, + {file = "mysql_connector_python-8.4.0-cp38-cp38-manylinux_2_17_x86_64.whl", hash = "sha256:e6d5a418ef124dd1b18a73fd89431a1862ce7bf68f61275c7d006e8e2f8afcd2"}, + {file = "mysql_connector_python-8.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:427a84027b8314c73f5ff3eb1abdc709a8201b44a491d7b580bdf430b4820a16"}, + {file = "mysql_connector_python-8.4.0-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:44a99d44a925ea29c2e423e6d8b1d97ce740c3078d8b41923a81bbcd0a821972"}, + {file = "mysql_connector_python-8.4.0-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:ed276c4e7907da0ad95a9ad122004294d6fb425127064af2ae880033b8e72166"}, + {file = "mysql_connector_python-8.4.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:2b5c6fea6513cf208c7116a4a5e36b3ae54e0d37f324a7cfe43fb01cfdf03be6"}, + {file = "mysql_connector_python-8.4.0-cp39-cp39-manylinux_2_17_x86_64.whl", hash = "sha256:651c7824af57eb50f4a79ea04bf6f453b24381e1bb56eee45c0035b4c0c624c0"}, + {file = "mysql_connector_python-8.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:655dccbdc0e2943e62cf69e10a024329248b17b58bfac59c60fd2103db3ba0b0"}, + {file = "mysql_connector_python-8.4.0-py2.py3-none-any.whl", hash = "sha256:35939c4ff28f395a5550bae67bafa4d1658ea72ea3206f457fff64a0fbec17e4"}, +] + +[package.extras] +dns-srv = ["dnspython (>=1.16.0,<=2.3.0)"] +fido2 = ["fido2 (==1.1.2)"] +gssapi = ["gssapi (>=1.6.9,<=1.8.2)"] +opentelemetry = ["Deprecated (>=1.2.6)", "typing-extensions (>=3.7.4)", "zipp (>=0.5)"] + +[[package]] +name = "nodeenv" +version = "1.9.1" +description = "Node.js virtual environment builder" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, +] + +[[package]] +name = "ordered-set" +version = "4.1.0" +description = "An OrderedSet is a custom MutableSet that remembers its order, so that every" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ordered-set-4.1.0.tar.gz", hash = "sha256:694a8e44c87657c59292ede72891eb91d34131f6531463aab3009191c77364a8"}, + {file = "ordered_set-4.1.0-py3-none-any.whl", hash = "sha256:046e1132c71fcf3330438a539928932caf51ddbc582496833e23de611de14562"}, +] + +[package.extras] +dev = ["black", "mypy", "pytest"] + +[[package]] +name = "packaging" +version = "24.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, +] + +[[package]] +name = "paginate" +version = "0.5.7" +description = "Divides large result sets into pages for easier browsing" +optional = false +python-versions = "*" +files = [ + {file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"}, + {file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"}, +] + +[package.extras] +dev = ["pytest", "tox"] +lint = ["black"] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "pendulum" +version = "3.0.0" +description = "Python datetimes made easy" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pendulum-3.0.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2cf9e53ef11668e07f73190c805dbdf07a1939c3298b78d5a9203a86775d1bfd"}, + {file = "pendulum-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fb551b9b5e6059377889d2d878d940fd0bbb80ae4810543db18e6f77b02c5ef6"}, + {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c58227ac260d5b01fc1025176d7b31858c9f62595737f350d22124a9a3ad82d"}, + {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60fb6f415fea93a11c52578eaa10594568a6716602be8430b167eb0d730f3332"}, + {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b69f6b4dbcb86f2c2fe696ba991e67347bcf87fe601362a1aba6431454b46bde"}, + {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:138afa9c373ee450ede206db5a5e9004fd3011b3c6bbe1e57015395cd076a09f"}, + {file = "pendulum-3.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:83d9031f39c6da9677164241fd0d37fbfc9dc8ade7043b5d6d62f56e81af8ad2"}, + {file = "pendulum-3.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0c2308af4033fa534f089595bcd40a95a39988ce4059ccd3dc6acb9ef14ca44a"}, + {file = "pendulum-3.0.0-cp310-none-win_amd64.whl", hash = "sha256:9a59637cdb8462bdf2dbcb9d389518c0263799189d773ad5c11db6b13064fa79"}, + {file = "pendulum-3.0.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3725245c0352c95d6ca297193192020d1b0c0f83d5ee6bb09964edc2b5a2d508"}, + {file = "pendulum-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6c035f03a3e565ed132927e2c1b691de0dbf4eb53b02a5a3c5a97e1a64e17bec"}, + {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597e66e63cbd68dd6d58ac46cb7a92363d2088d37ccde2dae4332ef23e95cd00"}, + {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99a0f8172e19f3f0c0e4ace0ad1595134d5243cf75985dc2233e8f9e8de263ca"}, + {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:77d8839e20f54706aed425bec82a83b4aec74db07f26acd039905d1237a5e1d4"}, + {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afde30e8146292b059020fbc8b6f8fd4a60ae7c5e6f0afef937bbb24880bdf01"}, + {file = "pendulum-3.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:660434a6fcf6303c4efd36713ca9212c753140107ee169a3fc6c49c4711c2a05"}, + {file = "pendulum-3.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dee9e5a48c6999dc1106eb7eea3e3a50e98a50651b72c08a87ee2154e544b33e"}, + {file = "pendulum-3.0.0-cp311-none-win_amd64.whl", hash = "sha256:d4cdecde90aec2d67cebe4042fd2a87a4441cc02152ed7ed8fb3ebb110b94ec4"}, + {file = "pendulum-3.0.0-cp311-none-win_arm64.whl", hash = "sha256:773c3bc4ddda2dda9f1b9d51fe06762f9200f3293d75c4660c19b2614b991d83"}, + {file = "pendulum-3.0.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:409e64e41418c49f973d43a28afe5df1df4f1dd87c41c7c90f1a63f61ae0f1f7"}, + {file = "pendulum-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a38ad2121c5ec7c4c190c7334e789c3b4624798859156b138fcc4d92295835dc"}, + {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fde4d0b2024b9785f66b7f30ed59281bd60d63d9213cda0eb0910ead777f6d37"}, + {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b2c5675769fb6d4c11238132962939b960fcb365436b6d623c5864287faa319"}, + {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8af95e03e066826f0f4c65811cbee1b3123d4a45a1c3a2b4fc23c4b0dff893b5"}, + {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2165a8f33cb15e06c67070b8afc87a62b85c5a273e3aaa6bc9d15c93a4920d6f"}, + {file = "pendulum-3.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ad5e65b874b5e56bd942546ea7ba9dd1d6a25121db1c517700f1c9de91b28518"}, + {file = "pendulum-3.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17fe4b2c844bbf5f0ece69cfd959fa02957c61317b2161763950d88fed8e13b9"}, + {file = "pendulum-3.0.0-cp312-none-win_amd64.whl", hash = "sha256:78f8f4e7efe5066aca24a7a57511b9c2119f5c2b5eb81c46ff9222ce11e0a7a5"}, + {file = "pendulum-3.0.0-cp312-none-win_arm64.whl", hash = "sha256:28f49d8d1e32aae9c284a90b6bb3873eee15ec6e1d9042edd611b22a94ac462f"}, + {file = "pendulum-3.0.0-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:d4e2512f4e1a4670284a153b214db9719eb5d14ac55ada5b76cbdb8c5c00399d"}, + {file = "pendulum-3.0.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:3d897eb50883cc58d9b92f6405245f84b9286cd2de6e8694cb9ea5cb15195a32"}, + {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e169cc2ca419517f397811bbe4589cf3cd13fca6dc38bb352ba15ea90739ebb"}, + {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f17c3084a4524ebefd9255513692f7e7360e23c8853dc6f10c64cc184e1217ab"}, + {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:826d6e258052715f64d05ae0fc9040c0151e6a87aae7c109ba9a0ed930ce4000"}, + {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2aae97087872ef152a0c40e06100b3665d8cb86b59bc8471ca7c26132fccd0f"}, + {file = "pendulum-3.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ac65eeec2250d03106b5e81284ad47f0d417ca299a45e89ccc69e36130ca8bc7"}, + {file = "pendulum-3.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a5346d08f3f4a6e9e672187faa179c7bf9227897081d7121866358af369f44f9"}, + {file = "pendulum-3.0.0-cp37-none-win_amd64.whl", hash = "sha256:235d64e87946d8f95c796af34818c76e0f88c94d624c268693c85b723b698aa9"}, + {file = "pendulum-3.0.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:6a881d9c2a7f85bc9adafcfe671df5207f51f5715ae61f5d838b77a1356e8b7b"}, + {file = "pendulum-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d7762d2076b9b1cb718a6631ad6c16c23fc3fac76cbb8c454e81e80be98daa34"}, + {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e8e36a8130819d97a479a0e7bf379b66b3b1b520e5dc46bd7eb14634338df8c"}, + {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7dc843253ac373358ffc0711960e2dd5b94ab67530a3e204d85c6e8cb2c5fa10"}, + {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a78ad3635d609ceb1e97d6aedef6a6a6f93433ddb2312888e668365908c7120"}, + {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b30a137e9e0d1f751e60e67d11fc67781a572db76b2296f7b4d44554761049d6"}, + {file = "pendulum-3.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c95984037987f4a457bb760455d9ca80467be792236b69d0084f228a8ada0162"}, + {file = "pendulum-3.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d29c6e578fe0f893766c0d286adbf0b3c726a4e2341eba0917ec79c50274ec16"}, + {file = "pendulum-3.0.0-cp38-none-win_amd64.whl", hash = "sha256:deaba8e16dbfcb3d7a6b5fabdd5a38b7c982809567479987b9c89572df62e027"}, + {file = "pendulum-3.0.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b11aceea5b20b4b5382962b321dbc354af0defe35daa84e9ff3aae3c230df694"}, + {file = "pendulum-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a90d4d504e82ad236afac9adca4d6a19e4865f717034fc69bafb112c320dcc8f"}, + {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:825799c6b66e3734227756fa746cc34b3549c48693325b8b9f823cb7d21b19ac"}, + {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad769e98dc07972e24afe0cff8d365cb6f0ebc7e65620aa1976fcfbcadc4c6f3"}, + {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6fc26907eb5fb8cc6188cc620bc2075a6c534d981a2f045daa5f79dfe50d512"}, + {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c717eab1b6d898c00a3e0fa7781d615b5c5136bbd40abe82be100bb06df7a56"}, + {file = "pendulum-3.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3ddd1d66d1a714ce43acfe337190be055cdc221d911fc886d5a3aae28e14b76d"}, + {file = "pendulum-3.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:822172853d7a9cf6da95d7b66a16c7160cb99ae6df55d44373888181d7a06edc"}, + {file = "pendulum-3.0.0-cp39-none-win_amd64.whl", hash = "sha256:840de1b49cf1ec54c225a2a6f4f0784d50bd47f68e41dc005b7f67c7d5b5f3ae"}, + {file = "pendulum-3.0.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3b1f74d1e6ffe5d01d6023870e2ce5c2191486928823196f8575dcc786e107b1"}, + {file = "pendulum-3.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:729e9f93756a2cdfa77d0fc82068346e9731c7e884097160603872686e570f07"}, + {file = "pendulum-3.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e586acc0b450cd21cbf0db6bae386237011b75260a3adceddc4be15334689a9a"}, + {file = "pendulum-3.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22e7944ffc1f0099a79ff468ee9630c73f8c7835cd76fdb57ef7320e6a409df4"}, + {file = "pendulum-3.0.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fa30af36bd8e50686846bdace37cf6707bdd044e5cb6e1109acbad3277232e04"}, + {file = "pendulum-3.0.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:440215347b11914ae707981b9a57ab9c7b6983ab0babde07063c6ee75c0dc6e7"}, + {file = "pendulum-3.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:314c4038dc5e6a52991570f50edb2f08c339debdf8cea68ac355b32c4174e820"}, + {file = "pendulum-3.0.0-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5acb1d386337415f74f4d1955c4ce8d0201978c162927d07df8eb0692b2d8533"}, + {file = "pendulum-3.0.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a789e12fbdefaffb7b8ac67f9d8f22ba17a3050ceaaa635cd1cc4645773a4b1e"}, + {file = "pendulum-3.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:860aa9b8a888e5913bd70d819306749e5eb488e6b99cd6c47beb701b22bdecf5"}, + {file = "pendulum-3.0.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:5ebc65ea033ef0281368217fbf59f5cb05b338ac4dd23d60959c7afcd79a60a0"}, + {file = "pendulum-3.0.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d9fef18ab0386ef6a9ac7bad7e43ded42c83ff7ad412f950633854f90d59afa8"}, + {file = "pendulum-3.0.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1c134ba2f0571d0b68b83f6972e2307a55a5a849e7dac8505c715c531d2a8795"}, + {file = "pendulum-3.0.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:385680812e7e18af200bb9b4a49777418c32422d05ad5a8eb85144c4a285907b"}, + {file = "pendulum-3.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eec91cd87c59fb32ec49eb722f375bd58f4be790cae11c1b70fac3ee4f00da0"}, + {file = "pendulum-3.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4386bffeca23c4b69ad50a36211f75b35a4deb6210bdca112ac3043deb7e494a"}, + {file = "pendulum-3.0.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dfbcf1661d7146d7698da4b86e7f04814221081e9fe154183e34f4c5f5fa3bf8"}, + {file = "pendulum-3.0.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:04a1094a5aa1daa34a6b57c865b25f691848c61583fb22722a4df5699f6bf74c"}, + {file = "pendulum-3.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5b0ec85b9045bd49dd3a3493a5e7ddfd31c36a2a60da387c419fa04abcaecb23"}, + {file = "pendulum-3.0.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0a15b90129765b705eb2039062a6daf4d22c4e28d1a54fa260892e8c3ae6e157"}, + {file = "pendulum-3.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:bb8f6d7acd67a67d6fedd361ad2958ff0539445ef51cbe8cd288db4306503cd0"}, + {file = "pendulum-3.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd69b15374bef7e4b4440612915315cc42e8575fcda2a3d7586a0d88192d0c88"}, + {file = "pendulum-3.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc00f8110db6898360c53c812872662e077eaf9c75515d53ecc65d886eec209a"}, + {file = "pendulum-3.0.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:83a44e8b40655d0ba565a5c3d1365d27e3e6778ae2a05b69124db9e471255c4a"}, + {file = "pendulum-3.0.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1a3604e9fbc06b788041b2a8b78f75c243021e0f512447806a6d37ee5214905d"}, + {file = "pendulum-3.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:92c307ae7accebd06cbae4729f0ba9fa724df5f7d91a0964b1b972a22baa482b"}, + {file = "pendulum-3.0.0.tar.gz", hash = "sha256:5d034998dea404ec31fae27af6b22cff1708f830a1ed7353be4d1019bb9f584e"}, +] + +[package.dependencies] +python-dateutil = ">=2.6" +time-machine = {version = ">=2.6.0", optional = true, markers = "implementation_name != \"pypy\" and extra == \"test\""} +tzdata = ">=2020.1" + +[package.extras] +test = ["time-machine (>=2.6.0)"] + +[[package]] +name = "platformdirs" +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pre-commit" +version = "3.8.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.9" +files = [ + {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, + {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + +[[package]] +name = "propcache" +version = "0.2.0" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.8" +files = [ + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336"}, + {file = "propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad"}, + {file = "propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b"}, + {file = "propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1"}, + {file = "propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348"}, + {file = "propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5"}, + {file = "propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544"}, + {file = "propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032"}, + {file = "propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed"}, + {file = "propcache-0.2.0-cp38-cp38-win32.whl", hash = "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d"}, + {file = "propcache-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798"}, + {file = "propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9"}, + {file = "propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df"}, + {file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"}, + {file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"}, +] + +[[package]] +name = "pycparser" +version = "2.22" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + +[[package]] +name = "pydantic" +version = "2.6.3" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.6.3-py3-none-any.whl", hash = "sha256:72c6034df47f46ccdf81869fddb81aade68056003900a8724a4f160700016a2a"}, + {file = "pydantic-2.6.3.tar.gz", hash = "sha256:e07805c4c7f5c6826e33a1d4c9d47950d7eaf34868e2690f8594d2e30241f11f"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +pydantic-core = "2.16.3" +typing-extensions = ">=4.6.1" + +[package.extras] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.16.3" +description = "" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, + {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, + {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, + {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, + {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, + {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, + {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, + {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, + {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, + {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, + {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, + {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, + {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, + {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pygments" +version = "2.18.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pyisemail" +version = "2.0.1" +description = "Simple, robust email validation" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyisemail-2.0.1-py3-none-any.whl", hash = "sha256:3d2bebd159f436673219d024a3f02bed1b468c793df9a5fa08d72b7d4b4f6cb4"}, + {file = "pyisemail-2.0.1.tar.gz", hash = "sha256:daf4b3fb2150a38f406b0aaba729e19fcd638a6d1c0549c25ff54c7b804618f8"}, +] + +[package.dependencies] +dnspython = ">=2.0.0" + +[[package]] +name = "pyjwt" +version = "2.10.0" +description = "JSON Web Token implementation in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "PyJWT-2.10.0-py3-none-any.whl", hash = "sha256:543b77207db656de204372350926bed5a86201c4cbff159f623f79c7bb487a15"}, + {file = "pyjwt-2.10.0.tar.gz", hash = "sha256:7628a7eb7938959ac1b26e819a1df0fd3259505627b575e4bad6d08f76db695c"}, +] + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + +[[package]] +name = "pymdown-extensions" +version = "10.12" +description = "Extension pack for Python Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pymdown_extensions-10.12-py3-none-any.whl", hash = "sha256:49f81412242d3527b8b4967b990df395c89563043bc51a3d2d7d500e52123b77"}, + {file = "pymdown_extensions-10.12.tar.gz", hash = "sha256:b0ee1e0b2bef1071a47891ab17003bfe5bf824a398e13f49f8ed653b699369a7"}, +] + +[package.dependencies] +markdown = ">=3.6" +pyyaml = "*" + +[package.extras] +extra = ["pygments (>=2.12)"] + +[[package]] +name = "pytest" +version = "8.3.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=1.5,<2" + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.21.2" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest_asyncio-0.21.2-py3-none-any.whl", hash = "sha256:ab664c88bb7998f711d8039cacd4884da6430886ae8bbd4eded552ed2004f16b"}, + {file = "pytest_asyncio-0.21.2.tar.gz", hash = "sha256:d67738fc232b94b326b9d060750beb16e0074210b98dd8b58a5239fa2a154f45"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] + +[[package]] +name = "pytest-cov" +version = "5.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytest-sugar" +version = "1.0.0" +description = "pytest-sugar is a plugin for pytest that changes the default look and feel of pytest (e.g. progressbar, show tests that fail instantly)." +optional = false +python-versions = "*" +files = [ + {file = "pytest-sugar-1.0.0.tar.gz", hash = "sha256:6422e83258f5b0c04ce7c632176c7732cab5fdb909cb39cca5c9139f81276c0a"}, + {file = "pytest_sugar-1.0.0-py3-none-any.whl", hash = "sha256:70ebcd8fc5795dc457ff8b69d266a4e2e8a74ae0c3edc749381c64b5246c8dfd"}, +] + +[package.dependencies] +packaging = ">=21.3" +pytest = ">=6.2.0" +termcolor = ">=2.1.0" + +[package.extras] +dev = ["black", "flake8", "pre-commit"] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-dotenv" +version = "1.0.1" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, + {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + +[[package]] +name = "python-multipart" +version = "0.0.9" +description = "A streaming multipart parser for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python_multipart-0.0.9-py3-none-any.whl", hash = "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"}, + {file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"}, +] + +[package.extras] +dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatch", "invoke (==2.2.0)", "more-itertools (==10.2.0)", "pbr (==6.0.0)", "pluggy (==1.4.0)", "py (==1.11.0)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.2.0)", "pyyaml (==6.0.1)", "ruff (==0.2.1)"] + +[[package]] +name = "python-slugify" +version = "8.0.4" +description = "A Python slugify application that also handles Unicode" +optional = false +python-versions = ">=3.7" +files = [ + {file = "python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856"}, + {file = "python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"}, +] + +[package.dependencies] +text-unidecode = ">=1.3" + +[package.extras] +unidecode = ["Unidecode (>=1.1.1)"] + +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +description = "A custom YAML tag for referencing environment variables in YAML files. " +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, + {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, +] + +[package.dependencies] +pyyaml = "*" + +[[package]] +name = "redis" +version = "5.2.0" +description = "Python client for Redis database and key-value store" +optional = false +python-versions = ">=3.8" +files = [ + {file = "redis-5.2.0-py3-none-any.whl", hash = "sha256:ae174f2bb3b1bf2b09d54bf3e51fbc1469cf6c10aa03e21141f51969801a7897"}, + {file = "redis-5.2.0.tar.gz", hash = "sha256:0b1087665a771b1ff2e003aa5bdd354f15a70c9e25d5a7dbf9c722c16528a7b0"}, +] + +[package.extras] +hiredis = ["hiredis (>=3.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==23.2.1)", "requests (>=2.31.0)"] + +[[package]] +name = "regex" +version = "2024.11.6" +description = "Alternative regular expression module, to replace re." +optional = false +python-versions = ">=3.8" +files = [ + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62"}, + {file = "regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e"}, + {file = "regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45"}, + {file = "regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9"}, + {file = "regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad"}, + {file = "regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54"}, + {file = "regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d"}, + {file = "regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff"}, + {file = "regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f"}, + {file = "regex-2024.11.6-cp38-cp38-win32.whl", hash = "sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4"}, + {file = "regex-2024.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b"}, + {file = "regex-2024.11.6-cp39-cp39-win32.whl", hash = "sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57"}, + {file = "regex-2024.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983"}, + {file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"}, +] + +[[package]] +name = "requests" +version = "2.32.3" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.8" +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rich" +version = "13.9.4" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, + {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "ruff" +version = "0.7.4" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.7.4-py3-none-linux_armv6l.whl", hash = "sha256:a4919925e7684a3f18e18243cd6bea7cfb8e968a6eaa8437971f681b7ec51478"}, + {file = "ruff-0.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfb365c135b830778dda8c04fb7d4280ed0b984e1aec27f574445231e20d6c63"}, + {file = "ruff-0.7.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:63a569b36bc66fbadec5beaa539dd81e0527cb258b94e29e0531ce41bacc1f20"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d06218747d361d06fd2fdac734e7fa92df36df93035db3dc2ad7aa9852cb109"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0cea28d0944f74ebc33e9f934238f15c758841f9f5edd180b5315c203293452"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80094ecd4793c68b2571b128f91754d60f692d64bc0d7272ec9197fdd09bf9ea"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:997512325c6620d1c4c2b15db49ef59543ef9cd0f4aa8065ec2ae5103cedc7e7"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00b4cf3a6b5fad6d1a66e7574d78956bbd09abfd6c8a997798f01f5da3d46a05"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7dbdc7d8274e1422722933d1edddfdc65b4336abf0b16dfcb9dedd6e6a517d06"}, + {file = "ruff-0.7.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e92dfb5f00eaedb1501b2f906ccabfd67b2355bdf117fea9719fc99ac2145bc"}, + {file = "ruff-0.7.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3bd726099f277d735dc38900b6a8d6cf070f80828877941983a57bca1cd92172"}, + {file = "ruff-0.7.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2e32829c429dd081ee5ba39aef436603e5b22335c3d3fff013cd585806a6486a"}, + {file = "ruff-0.7.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:662a63b4971807623f6f90c1fb664613f67cc182dc4d991471c23c541fee62dd"}, + {file = "ruff-0.7.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:876f5e09eaae3eb76814c1d3b68879891d6fde4824c015d48e7a7da4cf066a3a"}, + {file = "ruff-0.7.4-py3-none-win32.whl", hash = "sha256:75c53f54904be42dd52a548728a5b572344b50d9b2873d13a3f8c5e3b91f5cac"}, + {file = "ruff-0.7.4-py3-none-win_amd64.whl", hash = "sha256:745775c7b39f914238ed1f1b0bebed0b9155a17cd8bc0b08d3c87e4703b990d6"}, + {file = "ruff-0.7.4-py3-none-win_arm64.whl", hash = "sha256:11bff065102c3ae9d3ea4dc9ecdfe5a5171349cdd0787c1fc64761212fc9cf1f"}, + {file = "ruff-0.7.4.tar.gz", hash = "sha256:cd12e35031f5af6b9b93715d8c4f40360070b2041f81273d0527683d5708fce2"}, +] + +[[package]] +name = "setuptools" +version = "75.6.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.9" +files = [ + {file = "setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d"}, + {file = "setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.7.0)"] +core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"] + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = false +python-versions = ">=3.7" +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "sql-smith" +version = "1.1.1" +description = "sql-smith is an SQL query builder with zero dependencies and a fluent interface." +optional = false +python-versions = ">=3.10,<4.0" +files = [ + {file = "sql_smith-1.1.1-py3-none-any.whl", hash = "sha256:f092a1816ee7bfd740cd381a38c2d4524e101f580eec0cb8ec6882ee8f90bbed"}, + {file = "sql_smith-1.1.1.tar.gz", hash = "sha256:5622205e4f8f1815ddb0bd347a0bc6bece507d2fccaa948f867f407dd6cf9c3d"}, +] + +[[package]] +name = "starlette" +version = "0.37.2" +description = "The little ASGI library that shines." +optional = false +python-versions = ">=3.8" +files = [ + {file = "starlette-0.37.2-py3-none-any.whl", hash = "sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee"}, + {file = "starlette-0.37.2.tar.gz", hash = "sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823"}, +] + +[package.dependencies] +anyio = ">=3.4.0,<5" + +[package.extras] +full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] + +[[package]] +name = "termcolor" +version = "2.5.0" +description = "ANSI color formatting for output in terminal" +optional = false +python-versions = ">=3.9" +files = [ + {file = "termcolor-2.5.0-py3-none-any.whl", hash = "sha256:37b17b5fc1e604945c2642c872a3764b5d547a48009871aea3edd3afa180afb8"}, + {file = "termcolor-2.5.0.tar.gz", hash = "sha256:998d8d27da6d48442e8e1f016119076b690d962507531df4890fcd2db2ef8a6f"}, +] + +[package.extras] +tests = ["pytest", "pytest-cov"] + +[[package]] +name = "text-unidecode" +version = "1.3" +description = "The most basic Text::Unidecode port" +optional = false +python-versions = "*" +files = [ + {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, + {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, +] + +[[package]] +name = "time-machine" +version = "2.16.0" +description = "Travel through time in your tests." +optional = false +python-versions = ">=3.9" +files = [ + {file = "time_machine-2.16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:09531af59fdfb39bfd24d28bd1e837eff5a5d98318509a31b6cfd57d27801e52"}, + {file = "time_machine-2.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:92d0b0f3c49f34dd76eb462f0afdc61ed1cb318c06c46d03e99b44ebb489bdad"}, + {file = "time_machine-2.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c29616e18e2349a8766d5b6817920fc74e39c00fa375d202231e9d525a1b882"}, + {file = "time_machine-2.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c1ceb6035a64cb00650e3ab203cf3faffac18576a3f3125c24df468b784077c7"}, + {file = "time_machine-2.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64c205ea37b8c4ba232645335fc3b75bc2d03ce30f0a34649e36cae85652ee96"}, + {file = "time_machine-2.16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dfe92412bd11104c4f0fb2da68653e6c45b41f7217319a83a8b66ed4f20148b3"}, + {file = "time_machine-2.16.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d5fe7a6284e3dce87ae13a25029c53542dd27a28d151f3ef362ec4dd9c3e45fd"}, + {file = "time_machine-2.16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c0fca3025266d88d1b48be162a43b7c2d91c81cc5b3bee9f01194678ffb9969a"}, + {file = "time_machine-2.16.0-cp310-cp310-win32.whl", hash = "sha256:4149e17018af07a5756a1df84aea71e6e178598c358c860c6bfec42170fa7970"}, + {file = "time_machine-2.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:01bc257e9418980a4922de94775be42a966e1a082fb01a1635917f9afc7b84ca"}, + {file = "time_machine-2.16.0-cp310-cp310-win_arm64.whl", hash = "sha256:6895e3e84119594ab12847c928f619d40ae9cedd0755515dc154a5b5dc6edd9f"}, + {file = "time_machine-2.16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8f936566ef9f09136a3d5db305961ef6d897b76b240c9ff4199144aed6dd4fe5"}, + {file = "time_machine-2.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5886e23ede3478ca2a3e0a641f5d09dd784dfa9e48c96e8e5e31fc4fe77b6dc0"}, + {file = "time_machine-2.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c76caf539fa4941e1817b7c482c87c65c52a1903fea761e84525955c6106fafb"}, + {file = "time_machine-2.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:298aa423e07c8b21b991782f01d7749c871c792319c2af3e9755f9ab49033212"}, + {file = "time_machine-2.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391ae9c484736850bb44ef125cbad52fe2d1b69e42c95dc88c43af8ead2cc7"}, + {file = "time_machine-2.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:503e7ff507c2089699d91885fc5b9c8ff16774a7b6aff48b4dcee0c0a0685b61"}, + {file = "time_machine-2.16.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:eee7b0fc4fbab2c6585ea17606c6548be83919c70deea0865409fe9fc2d8cdce"}, + {file = "time_machine-2.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9db5e5b3ccdadaafa5730c2f9db44c38b013234c9ad01f87738907e19bdba268"}, + {file = "time_machine-2.16.0-cp311-cp311-win32.whl", hash = "sha256:2552f0767bc10c9d668f108fef9b487809cdeb772439ce932e74136365c69baf"}, + {file = "time_machine-2.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:12474fcdbc475aa6fe5275fe7224e685c5b9777f5939647f35980e9614ae7558"}, + {file = "time_machine-2.16.0-cp311-cp311-win_arm64.whl", hash = "sha256:ac2df0fa564356384515ed62cb6679f33f1f529435b16b0ec0f88414635dbe39"}, + {file = "time_machine-2.16.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:84788f4d62a8b1bf5e499bb9b0e23ceceea21c415ad6030be6267ce3d639842f"}, + {file = "time_machine-2.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:15ec236b6571730236a193d9d6c11d472432fc6ab54e85eac1c16d98ddcd71bf"}, + {file = "time_machine-2.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cedc989717c8b44a3881ac3d68ab5a95820448796c550de6a2149ed1525157f0"}, + {file = "time_machine-2.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d26d79de1c63a8c6586c75967e09b0ff306aa7e944a1eaddb74595c9b1839ca"}, + {file = "time_machine-2.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:317b68b56a9c3731e0cf8886e0f94230727159e375988b36c60edce0ddbcb44a"}, + {file = "time_machine-2.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:43e1e18279759897be3293a255d53e6b1cb0364b69d9591d0b80c51e461c94b0"}, + {file = "time_machine-2.16.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e43adb22def972a29d2b147999b56897116085777a0fea182fd93ee45730611e"}, + {file = "time_machine-2.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0c766bea27a0600e36806d628ebc4b47178b12fcdfb6c24dc0a566a9c06bfe7f"}, + {file = "time_machine-2.16.0-cp312-cp312-win32.whl", hash = "sha256:6dae82ab647d107817e013db82223e20a9853fa88543fec853ae326382d03c2e"}, + {file = "time_machine-2.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:265462c77dc9576267c3c7f20707780a171a9fdbac93ac22e608c309efd68c33"}, + {file = "time_machine-2.16.0-cp312-cp312-win_arm64.whl", hash = "sha256:ef768e14768eebe3bb1196c0dece8e14c1c6991605721214a0c3c68cf77eb216"}, + {file = "time_machine-2.16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7751bf745d54e9e8b358c0afa332815da9b8a6194b26d0fd62876ab6c4d5c9c0"}, + {file = "time_machine-2.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1784edf173ca840ba154de6eed000b5727f65ab92972c2f88cec5c4d6349c5f2"}, + {file = "time_machine-2.16.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f5876a5682ce1f517e55d7ace2383432627889f6f7e338b961f99d684fd9e8d"}, + {file = "time_machine-2.16.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:806672529a2e255cd901f244c9033767dc1fa53466d0d3e3e49565a1572a64fe"}, + {file = "time_machine-2.16.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:667b150fedb54acdca2a4bea5bf6da837b43e6dd12857301b48191f8803ba93f"}, + {file = "time_machine-2.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:da3ae1028af240c0c46c79adf9c1acffecc6ed1701f2863b8132f5ceae6ae4b5"}, + {file = "time_machine-2.16.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:520a814ea1b2706c89ab260a54023033d3015abef25c77873b83e3d7c1fafbb2"}, + {file = "time_machine-2.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8243664438bb468408b29c6865958662d75e51f79c91842d2794fa22629eb697"}, + {file = "time_machine-2.16.0-cp313-cp313-win32.whl", hash = "sha256:32d445ce20d25c60ab92153c073942b0bac9815bfbfd152ce3dcc225d15ce988"}, + {file = "time_machine-2.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:f6927dda86425f97ffda36131f297b1a601c64a6ee6838bfa0e6d3149c2f0d9f"}, + {file = "time_machine-2.16.0-cp313-cp313-win_arm64.whl", hash = "sha256:4d3843143c46dddca6491a954bbd0abfd435681512ac343169560e9bab504129"}, + {file = "time_machine-2.16.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:23c5283c01b4f80b7dfbc88f3d8088c06c301b94b7c35366be498c2d7b308549"}, + {file = "time_machine-2.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ac95ae4529d7d85b251f9cf0f961a8a408ba285875811268f469d824a3b0b15a"}, + {file = "time_machine-2.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfb76674db946a74f0ca6e3b81caa8265e35dafe9b7005c7d2b8dd5bbd3825cf"}, + {file = "time_machine-2.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0b6ff3ccde9b16bbc694a2b5facf2d8890554f3135ff626ed1429e270e3cc4f"}, + {file = "time_machine-2.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1906ec6e26e6b803cd6aab28d420c87285b9c209ff2a69f82d12f82278f78bb"}, + {file = "time_machine-2.16.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e46bd09c944ec7a20868abd2b83d7d7abdaf427775e9df3089b9226a122b340f"}, + {file = "time_machine-2.16.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:cac3e2b4101db296b150cb665e5461c03621e6ede6117fc9d5048c0ec96d6e7c"}, + {file = "time_machine-2.16.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e0dcc97cfec12ae306e3036746e7631cc7ef65c31889f7264c25217d4938367"}, + {file = "time_machine-2.16.0-cp39-cp39-win32.whl", hash = "sha256:c761d32d0c5d1fe5b71ac502e1bd5edec4598a7fc6f607b9b906b98e911148ce"}, + {file = "time_machine-2.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:ddfab1c622342f2945942c5c2d6be327656980e8f2d2b2ce0c022d0aa3711361"}, + {file = "time_machine-2.16.0-cp39-cp39-win_arm64.whl", hash = "sha256:2e08a4015d5d1aab2cb46c780e85b33efcd5cbe880bb363b282a6972e617b8bb"}, + {file = "time_machine-2.16.0.tar.gz", hash = "sha256:4a99acc273d2f98add23a89b94d4dd9e14969c01214c8514bfa78e4e9364c7e2"}, +] + +[package.dependencies] +python-dateutil = "*" + +[[package]] +name = "tomli" +version = "2.1.0" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, + {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, +] + +[[package]] +name = "typer" +version = "0.9.4" +description = "Typer, build great CLIs. Easy to code. Based on Python type hints." +optional = false +python-versions = ">=3.6" +files = [ + {file = "typer-0.9.4-py3-none-any.whl", hash = "sha256:aa6c4a4e2329d868b80ecbaf16f807f2b54e192209d7ac9dd42691d63f7a54eb"}, + {file = "typer-0.9.4.tar.gz", hash = "sha256:f714c2d90afae3a7929fcd72a3abb08df305e1ff61719381384211c4070af57f"}, +] + +[package.dependencies] +click = ">=7.1.1,<9.0.0" +colorama = {version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"all\""} +rich = {version = ">=10.11.0,<14.0.0", optional = true, markers = "extra == \"all\""} +shellingham = {version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"all\""} +typing-extensions = ">=3.7.4.3" + +[package.extras] +all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] +dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] +doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] +test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.971)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + +[[package]] +name = "tzdata" +version = "2024.2" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, + {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, +] + +[[package]] +name = "urllib3" +version = "2.2.3" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "uvicorn" +version = "0.27.1" +description = "The lightning-fast ASGI server." +optional = false +python-versions = ">=3.8" +files = [ + {file = "uvicorn-0.27.1-py3-none-any.whl", hash = "sha256:5c89da2f3895767472a35556e539fd59f7edbe9b1e9c0e1c99eebeadc61838e4"}, + {file = "uvicorn-0.27.1.tar.gz", hash = "sha256:3d9a267296243532db80c83a959a3400502165ade2c1338dea4e67915fd4745a"}, +] + +[package.dependencies] +click = ">=7.0" +colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} +h11 = ">=0.8" +httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} +python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} +uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} +websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} + +[package.extras] +standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[[package]] +name = "uvloop" +version = "0.21.0" +description = "Fast implementation of asyncio event loop on top of libuv" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f"}, + {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d"}, + {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26"}, + {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb"}, + {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f"}, + {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c"}, + {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8"}, + {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0"}, + {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e"}, + {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb"}, + {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6"}, + {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d"}, + {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c"}, + {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2"}, + {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d"}, + {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc"}, + {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb"}, + {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f"}, + {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281"}, + {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af"}, + {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6"}, + {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816"}, + {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc"}, + {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553"}, + {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:17df489689befc72c39a08359efac29bbee8eee5209650d4b9f34df73d22e414"}, + {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc09f0ff191e61c2d592a752423c767b4ebb2986daa9ed62908e2b1b9a9ae206"}, + {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0ce1b49560b1d2d8a2977e3ba4afb2414fb46b86a1b64056bc4ab929efdafbe"}, + {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e678ad6fe52af2c58d2ae3c73dc85524ba8abe637f134bf3564ed07f555c5e79"}, + {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:460def4412e473896ef179a1671b40c039c7012184b627898eea5072ef6f017a"}, + {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:10da8046cc4a8f12c91a1c39d1dd1585c41162a15caaef165c2174db9ef18bdc"}, + {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c097078b8031190c934ed0ebfee8cc5f9ba9642e6eb88322b9958b649750f72b"}, + {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46923b0b5ee7fc0020bef24afe7836cb068f5050ca04caf6b487c513dc1a20b2"}, + {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53e420a3afe22cdcf2a0f4846e377d16e718bc70103d7088a4f7623567ba5fb0"}, + {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88cb67cdbc0e483da00af0b2c3cdad4b7c61ceb1ee0f33fe00e09c81e3a6cb75"}, + {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:221f4f2a1f46032b403bf3be628011caf75428ee3cc204a22addf96f586b19fd"}, + {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2d1f581393673ce119355d56da84fe1dd9d2bb8b3d13ce792524e1607139feff"}, + {file = "uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3"}, +] + +[package.extras] +dev = ["Cython (>=3.0,<4.0)", "setuptools (>=60)"] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["aiohttp (>=3.10.5)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] + +[[package]] +name = "virtualenv" +version = "20.27.1" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.8" +files = [ + {file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"}, + {file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + +[[package]] +name = "watchdog" +version = "6.0.0" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.9" +files = [ + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2"}, + {file = "watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a"}, + {file = "watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"}, + {file = "watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f"}, + {file = "watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + +[[package]] +name = "watchfiles" +version = "0.24.0" +description = "Simple, modern and high performance file watching and code reload in python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "watchfiles-0.24.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:083dc77dbdeef09fa44bb0f4d1df571d2e12d8a8f985dccde71ac3ac9ac067a0"}, + {file = "watchfiles-0.24.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e94e98c7cb94cfa6e071d401ea3342767f28eb5a06a58fafdc0d2a4974f4f35c"}, + {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82ae557a8c037c42a6ef26c494d0631cacca040934b101d001100ed93d43f361"}, + {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:acbfa31e315a8f14fe33e3542cbcafc55703b8f5dcbb7c1eecd30f141df50db3"}, + {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b74fdffce9dfcf2dc296dec8743e5b0332d15df19ae464f0e249aa871fc1c571"}, + {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:449f43f49c8ddca87c6b3980c9284cab6bd1f5c9d9a2b00012adaaccd5e7decd"}, + {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4abf4ad269856618f82dee296ac66b0cd1d71450fc3c98532d93798e73399b7a"}, + {file = "watchfiles-0.24.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f895d785eb6164678ff4bb5cc60c5996b3ee6df3edb28dcdeba86a13ea0465e"}, + {file = "watchfiles-0.24.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7ae3e208b31be8ce7f4c2c0034f33406dd24fbce3467f77223d10cd86778471c"}, + {file = "watchfiles-0.24.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2efec17819b0046dde35d13fb8ac7a3ad877af41ae4640f4109d9154ed30a188"}, + {file = "watchfiles-0.24.0-cp310-none-win32.whl", hash = "sha256:6bdcfa3cd6fdbdd1a068a52820f46a815401cbc2cb187dd006cb076675e7b735"}, + {file = "watchfiles-0.24.0-cp310-none-win_amd64.whl", hash = "sha256:54ca90a9ae6597ae6dc00e7ed0a040ef723f84ec517d3e7ce13e63e4bc82fa04"}, + {file = "watchfiles-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:bdcd5538e27f188dd3c804b4a8d5f52a7fc7f87e7fd6b374b8e36a4ca03db428"}, + {file = "watchfiles-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2dadf8a8014fde6addfd3c379e6ed1a981c8f0a48292d662e27cabfe4239c83c"}, + {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6509ed3f467b79d95fc62a98229f79b1a60d1b93f101e1c61d10c95a46a84f43"}, + {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8360f7314a070c30e4c976b183d1d8d1585a4a50c5cb603f431cebcbb4f66327"}, + {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:316449aefacf40147a9efaf3bd7c9bdd35aaba9ac5d708bd1eb5763c9a02bef5"}, + {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73bde715f940bea845a95247ea3e5eb17769ba1010efdc938ffcb967c634fa61"}, + {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3770e260b18e7f4e576edca4c0a639f704088602e0bc921c5c2e721e3acb8d15"}, + {file = "watchfiles-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa0fd7248cf533c259e59dc593a60973a73e881162b1a2f73360547132742823"}, + {file = "watchfiles-0.24.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d7a2e3b7f5703ffbd500dabdefcbc9eafeff4b9444bbdd5d83d79eedf8428fab"}, + {file = "watchfiles-0.24.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d831ee0a50946d24a53821819b2327d5751b0c938b12c0653ea5be7dea9c82ec"}, + {file = "watchfiles-0.24.0-cp311-none-win32.whl", hash = "sha256:49d617df841a63b4445790a254013aea2120357ccacbed00253f9c2b5dc24e2d"}, + {file = "watchfiles-0.24.0-cp311-none-win_amd64.whl", hash = "sha256:d3dcb774e3568477275cc76554b5a565024b8ba3a0322f77c246bc7111c5bb9c"}, + {file = "watchfiles-0.24.0-cp311-none-win_arm64.whl", hash = "sha256:9301c689051a4857d5b10777da23fafb8e8e921bcf3abe6448a058d27fb67633"}, + {file = "watchfiles-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a"}, + {file = "watchfiles-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370"}, + {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6"}, + {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b"}, + {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e"}, + {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea"}, + {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f"}, + {file = "watchfiles-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234"}, + {file = "watchfiles-0.24.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef"}, + {file = "watchfiles-0.24.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968"}, + {file = "watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444"}, + {file = "watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896"}, + {file = "watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418"}, + {file = "watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48"}, + {file = "watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90"}, + {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94"}, + {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e"}, + {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827"}, + {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df"}, + {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab"}, + {file = "watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f"}, + {file = "watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b"}, + {file = "watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18"}, + {file = "watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07"}, + {file = "watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366"}, + {file = "watchfiles-0.24.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ee82c98bed9d97cd2f53bdb035e619309a098ea53ce525833e26b93f673bc318"}, + {file = "watchfiles-0.24.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fd92bbaa2ecdb7864b7600dcdb6f2f1db6e0346ed425fbd01085be04c63f0b05"}, + {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f83df90191d67af5a831da3a33dd7628b02a95450e168785586ed51e6d28943c"}, + {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fca9433a45f18b7c779d2bae7beeec4f740d28b788b117a48368d95a3233ed83"}, + {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b995bfa6bf01a9e09b884077a6d37070464b529d8682d7691c2d3b540d357a0c"}, + {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed9aba6e01ff6f2e8285e5aa4154e2970068fe0fc0998c4380d0e6278222269b"}, + {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5171ef898299c657685306d8e1478a45e9303ddcd8ac5fed5bd52ad4ae0b69b"}, + {file = "watchfiles-0.24.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4933a508d2f78099162da473841c652ad0de892719043d3f07cc83b33dfd9d91"}, + {file = "watchfiles-0.24.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95cf3b95ea665ab03f5a54765fa41abf0529dbaf372c3b83d91ad2cfa695779b"}, + {file = "watchfiles-0.24.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:01def80eb62bd5db99a798d5e1f5f940ca0a05986dcfae21d833af7a46f7ee22"}, + {file = "watchfiles-0.24.0-cp38-none-win32.whl", hash = "sha256:4d28cea3c976499475f5b7a2fec6b3a36208656963c1a856d328aeae056fc5c1"}, + {file = "watchfiles-0.24.0-cp38-none-win_amd64.whl", hash = "sha256:21ab23fdc1208086d99ad3f69c231ba265628014d4aed31d4e8746bd59e88cd1"}, + {file = "watchfiles-0.24.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b665caeeda58625c3946ad7308fbd88a086ee51ccb706307e5b1fa91556ac886"}, + {file = "watchfiles-0.24.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5c51749f3e4e269231510da426ce4a44beb98db2dce9097225c338f815b05d4f"}, + {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82b2509f08761f29a0fdad35f7e1638b8ab1adfa2666d41b794090361fb8b855"}, + {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a60e2bf9dc6afe7f743e7c9b149d1fdd6dbf35153c78fe3a14ae1a9aee3d98b"}, + {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7d9b87c4c55e3ea8881dfcbf6d61ea6775fffed1fedffaa60bd047d3c08c430"}, + {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:78470906a6be5199524641f538bd2c56bb809cd4bf29a566a75051610bc982c3"}, + {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07cdef0c84c03375f4e24642ef8d8178e533596b229d32d2bbd69e5128ede02a"}, + {file = "watchfiles-0.24.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d337193bbf3e45171c8025e291530fb7548a93c45253897cd764a6a71c937ed9"}, + {file = "watchfiles-0.24.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ec39698c45b11d9694a1b635a70946a5bad066b593af863460a8e600f0dff1ca"}, + {file = "watchfiles-0.24.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e28d91ef48eab0afb939fa446d8ebe77e2f7593f5f463fd2bb2b14132f95b6e"}, + {file = "watchfiles-0.24.0-cp39-none-win32.whl", hash = "sha256:7138eff8baa883aeaa074359daabb8b6c1e73ffe69d5accdc907d62e50b1c0da"}, + {file = "watchfiles-0.24.0-cp39-none-win_amd64.whl", hash = "sha256:b3ef2c69c655db63deb96b3c3e587084612f9b1fa983df5e0c3379d41307467f"}, + {file = "watchfiles-0.24.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:632676574429bee8c26be8af52af20e0c718cc7f5f67f3fb658c71928ccd4f7f"}, + {file = "watchfiles-0.24.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a2a9891723a735d3e2540651184be6fd5b96880c08ffe1a98bae5017e65b544b"}, + {file = "watchfiles-0.24.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a7fa2bc0efef3e209a8199fd111b8969fe9db9c711acc46636686331eda7dd4"}, + {file = "watchfiles-0.24.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01550ccf1d0aed6ea375ef259706af76ad009ef5b0203a3a4cce0f6024f9b68a"}, + {file = "watchfiles-0.24.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:96619302d4374de5e2345b2b622dc481257a99431277662c30f606f3e22f42be"}, + {file = "watchfiles-0.24.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:85d5f0c7771dcc7a26c7a27145059b6bb0ce06e4e751ed76cdf123d7039b60b5"}, + {file = "watchfiles-0.24.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:951088d12d339690a92cef2ec5d3cfd957692834c72ffd570ea76a6790222777"}, + {file = "watchfiles-0.24.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49fb58bcaa343fedc6a9e91f90195b20ccb3135447dc9e4e2570c3a39565853e"}, + {file = "watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1"}, +] + +[package.dependencies] +anyio = ">=3.0.0" + +[[package]] +name = "websockets" +version = "14.1" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.9" +files = [ + {file = "websockets-14.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a0adf84bc2e7c86e8a202537b4fd50e6f7f0e4a6b6bf64d7ccb96c4cd3330b29"}, + {file = "websockets-14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90b5d9dfbb6d07a84ed3e696012610b6da074d97453bd01e0e30744b472c8179"}, + {file = "websockets-14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2177ee3901075167f01c5e335a6685e71b162a54a89a56001f1c3e9e3d2ad250"}, + {file = "websockets-14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f14a96a0034a27f9d47fd9788913924c89612225878f8078bb9d55f859272b0"}, + {file = "websockets-14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f874ba705deea77bcf64a9da42c1f5fc2466d8f14daf410bc7d4ceae0a9fcb0"}, + {file = "websockets-14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9607b9a442392e690a57909c362811184ea429585a71061cd5d3c2b98065c199"}, + {file = "websockets-14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bea45f19b7ca000380fbd4e02552be86343080120d074b87f25593ce1700ad58"}, + {file = "websockets-14.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:219c8187b3ceeadbf2afcf0f25a4918d02da7b944d703b97d12fb01510869078"}, + {file = "websockets-14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad2ab2547761d79926effe63de21479dfaf29834c50f98c4bf5b5480b5838434"}, + {file = "websockets-14.1-cp310-cp310-win32.whl", hash = "sha256:1288369a6a84e81b90da5dbed48610cd7e5d60af62df9851ed1d1d23a9069f10"}, + {file = "websockets-14.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0744623852f1497d825a49a99bfbec9bea4f3f946df6eb9d8a2f0c37a2fec2e"}, + {file = "websockets-14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:449d77d636f8d9c17952628cc7e3b8faf6e92a17ec581ec0c0256300717e1512"}, + {file = "websockets-14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a35f704be14768cea9790d921c2c1cc4fc52700410b1c10948511039be824aac"}, + {file = "websockets-14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b1f3628a0510bd58968c0f60447e7a692933589b791a6b572fcef374053ca280"}, + {file = "websockets-14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c3deac3748ec73ef24fc7be0b68220d14d47d6647d2f85b2771cb35ea847aa1"}, + {file = "websockets-14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7048eb4415d46368ef29d32133134c513f507fff7d953c18c91104738a68c3b3"}, + {file = "websockets-14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cf0ad281c979306a6a34242b371e90e891bce504509fb6bb5246bbbf31e7b6"}, + {file = "websockets-14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cc1fc87428c1d18b643479caa7b15db7d544652e5bf610513d4a3478dbe823d0"}, + {file = "websockets-14.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f95ba34d71e2fa0c5d225bde3b3bdb152e957150100e75c86bc7f3964c450d89"}, + {file = "websockets-14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9481a6de29105d73cf4515f2bef8eb71e17ac184c19d0b9918a3701c6c9c4f23"}, + {file = "websockets-14.1-cp311-cp311-win32.whl", hash = "sha256:368a05465f49c5949e27afd6fbe0a77ce53082185bbb2ac096a3a8afaf4de52e"}, + {file = "websockets-14.1-cp311-cp311-win_amd64.whl", hash = "sha256:6d24fc337fc055c9e83414c94e1ee0dee902a486d19d2a7f0929e49d7d604b09"}, + {file = "websockets-14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed907449fe5e021933e46a3e65d651f641975a768d0649fee59f10c2985529ed"}, + {file = "websockets-14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:87e31011b5c14a33b29f17eb48932e63e1dcd3fa31d72209848652310d3d1f0d"}, + {file = "websockets-14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bc6ccf7d54c02ae47a48ddf9414c54d48af9c01076a2e1023e3b486b6e72c707"}, + {file = "websockets-14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9777564c0a72a1d457f0848977a1cbe15cfa75fa2f67ce267441e465717dcf1a"}, + {file = "websockets-14.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a655bde548ca98f55b43711b0ceefd2a88a71af6350b0c168aa77562104f3f45"}, + {file = "websockets-14.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfff83ca578cada2d19e665e9c8368e1598d4e787422a460ec70e531dbdd58"}, + {file = "websockets-14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6a6c9bcf7cdc0fd41cc7b7944447982e8acfd9f0d560ea6d6845428ed0562058"}, + {file = "websockets-14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4b6caec8576e760f2c7dd878ba817653144d5f369200b6ddf9771d64385b84d4"}, + {file = "websockets-14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eb6d38971c800ff02e4a6afd791bbe3b923a9a57ca9aeab7314c21c84bf9ff05"}, + {file = "websockets-14.1-cp312-cp312-win32.whl", hash = "sha256:1d045cbe1358d76b24d5e20e7b1878efe578d9897a25c24e6006eef788c0fdf0"}, + {file = "websockets-14.1-cp312-cp312-win_amd64.whl", hash = "sha256:90f4c7a069c733d95c308380aae314f2cb45bd8a904fb03eb36d1a4983a4993f"}, + {file = "websockets-14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3630b670d5057cd9e08b9c4dab6493670e8e762a24c2c94ef312783870736ab9"}, + {file = "websockets-14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36ebd71db3b89e1f7b1a5deaa341a654852c3518ea7a8ddfdf69cc66acc2db1b"}, + {file = "websockets-14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5b918d288958dc3fa1c5a0b9aa3256cb2b2b84c54407f4813c45d52267600cd3"}, + {file = "websockets-14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00fe5da3f037041da1ee0cf8e308374e236883f9842c7c465aa65098b1c9af59"}, + {file = "websockets-14.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8149a0f5a72ca36720981418eeffeb5c2729ea55fa179091c81a0910a114a5d2"}, + {file = "websockets-14.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77569d19a13015e840b81550922056acabc25e3f52782625bc6843cfa034e1da"}, + {file = "websockets-14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cf5201a04550136ef870aa60ad3d29d2a59e452a7f96b94193bee6d73b8ad9a9"}, + {file = "websockets-14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:88cf9163ef674b5be5736a584c999e98daf3aabac6e536e43286eb74c126b9c7"}, + {file = "websockets-14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:836bef7ae338a072e9d1863502026f01b14027250a4545672673057997d5c05a"}, + {file = "websockets-14.1-cp313-cp313-win32.whl", hash = "sha256:0d4290d559d68288da9f444089fd82490c8d2744309113fc26e2da6e48b65da6"}, + {file = "websockets-14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8621a07991add373c3c5c2cf89e1d277e49dc82ed72c75e3afc74bd0acc446f0"}, + {file = "websockets-14.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:01bb2d4f0a6d04538d3c5dfd27c0643269656c28045a53439cbf1c004f90897a"}, + {file = "websockets-14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:414ffe86f4d6f434a8c3b7913655a1a5383b617f9bf38720e7c0799fac3ab1c6"}, + {file = "websockets-14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8fda642151d5affdee8a430bd85496f2e2517be3a2b9d2484d633d5712b15c56"}, + {file = "websockets-14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd7c11968bc3860d5c78577f0dbc535257ccec41750675d58d8dc66aa47fe52c"}, + {file = "websockets-14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a032855dc7db987dff813583d04f4950d14326665d7e714d584560b140ae6b8b"}, + {file = "websockets-14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7e7ea2f782408c32d86b87a0d2c1fd8871b0399dd762364c731d86c86069a78"}, + {file = "websockets-14.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:39450e6215f7d9f6f7bc2a6da21d79374729f5d052333da4d5825af8a97e6735"}, + {file = "websockets-14.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ceada5be22fa5a5a4cdeec74e761c2ee7db287208f54c718f2df4b7e200b8d4a"}, + {file = "websockets-14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3fc753451d471cff90b8f467a1fc0ae64031cf2d81b7b34e1811b7e2691bc4bc"}, + {file = "websockets-14.1-cp39-cp39-win32.whl", hash = "sha256:14839f54786987ccd9d03ed7f334baec0f02272e7ec4f6e9d427ff584aeea8b4"}, + {file = "websockets-14.1-cp39-cp39-win_amd64.whl", hash = "sha256:d9fd19ecc3a4d5ae82ddbfb30962cf6d874ff943e56e0c81f5169be2fda62979"}, + {file = "websockets-14.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e5dc25a9dbd1a7f61eca4b7cb04e74ae4b963d658f9e4f9aad9cd00b688692c8"}, + {file = "websockets-14.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:04a97aca96ca2acedf0d1f332c861c5a4486fdcba7bcef35873820f940c4231e"}, + {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df174ece723b228d3e8734a6f2a6febbd413ddec39b3dc592f5a4aa0aff28098"}, + {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:034feb9f4286476f273b9a245fb15f02c34d9586a5bc936aff108c3ba1b21beb"}, + {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c308dabd2b380807ab64b62985eaccf923a78ebc572bd485375b9ca2b7dc7"}, + {file = "websockets-14.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5a42d3ecbb2db5080fc578314439b1d79eef71d323dc661aa616fb492436af5d"}, + {file = "websockets-14.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddaa4a390af911da6f680be8be4ff5aaf31c4c834c1a9147bc21cbcbca2d4370"}, + {file = "websockets-14.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a4c805c6034206143fbabd2d259ec5e757f8b29d0a2f0bf3d2fe5d1f60147a4a"}, + {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:205f672a6c2c671a86d33f6d47c9b35781a998728d2c7c2a3e1cf3333fcb62b7"}, + {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef440054124728cc49b01c33469de06755e5a7a4e83ef61934ad95fc327fbb0"}, + {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7591d6f440af7f73c4bd9404f3772bfee064e639d2b6cc8c94076e71b2471c1"}, + {file = "websockets-14.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:25225cc79cfebc95ba1d24cd3ab86aaa35bcd315d12fa4358939bd55e9bd74a5"}, + {file = "websockets-14.1-py3-none-any.whl", hash = "sha256:4d4fc827a20abe6d544a119896f6b78ee13fe81cbfef416f3f2ddf09a03f0e2e"}, + {file = "websockets-14.1.tar.gz", hash = "sha256:398b10c77d471c0aab20a845e7a60076b6390bfdaac7a6d2edb0d2c59d75e8d8"}, +] + +[[package]] +name = "win32-setctime" +version = "1.1.0" +description = "A small Python utility to set file creation time on Windows" +optional = false +python-versions = ">=3.5" +files = [ + {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, + {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, +] + +[package.extras] +dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] + +[[package]] +name = "yarl" +version = "1.18.0" +description = "Yet another URL library" +optional = false +python-versions = ">=3.9" +files = [ + {file = "yarl-1.18.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:074fee89caab89a97e18ef5f29060ef61ba3cae6cd77673acc54bfdd3214b7b7"}, + {file = "yarl-1.18.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b026cf2c32daf48d90c0c4e406815c3f8f4cfe0c6dfccb094a9add1ff6a0e41a"}, + {file = "yarl-1.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ae38bd86eae3ba3d2ce5636cc9e23c80c9db2e9cb557e40b98153ed102b5a736"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:685cc37f3f307c6a8e879986c6d85328f4c637f002e219f50e2ef66f7e062c1d"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8254dbfce84ee5d1e81051ee7a0f1536c108ba294c0fdb5933476398df0654f3"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20de4a8b04de70c49698dc2390b7fd2d18d424d3b876371f9b775e2b462d4b41"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0a2074a37285570d54b55820687de3d2f2b9ecf1b714e482e48c9e7c0402038"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f576ed278860df2721a5d57da3381040176ef1d07def9688a385c8330db61a1"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3a3709450a574d61be6ac53d582496014342ea34876af8dc17cc16da32826c9a"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bd80ed29761490c622edde5dd70537ca8c992c2952eb62ed46984f8eff66d6e8"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:32141e13a1d5a48525e519c9197d3f4d9744d818d5c7d6547524cc9eccc8971e"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8b8d3e4e014fb4274f1c5bf61511d2199e263909fb0b8bda2a7428b0894e8dc6"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:701bb4a8f4de191c8c0cc9a1e6d5142f4df880e9d1210e333b829ca9425570ed"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a45d94075ac0647621eaaf693c8751813a3eccac455d423f473ffed38c8ac5c9"}, + {file = "yarl-1.18.0-cp310-cp310-win32.whl", hash = "sha256:34176bfb082add67cb2a20abd85854165540891147f88b687a5ed0dc225750a0"}, + {file = "yarl-1.18.0-cp310-cp310-win_amd64.whl", hash = "sha256:73553bbeea7d6ec88c08ad8027f4e992798f0abc459361bf06641c71972794dc"}, + {file = "yarl-1.18.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b8e8c516dc4e1a51d86ac975b0350735007e554c962281c432eaa5822aa9765c"}, + {file = "yarl-1.18.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2e6b4466714a73f5251d84b471475850954f1fa6acce4d3f404da1d55d644c34"}, + {file = "yarl-1.18.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c893f8c1a6d48b25961e00922724732d00b39de8bb0b451307482dc87bddcd74"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13aaf2bdbc8c86ddce48626b15f4987f22e80d898818d735b20bd58f17292ee8"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd21c0128e301851de51bc607b0a6da50e82dc34e9601f4b508d08cc89ee7929"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:205de377bd23365cd85562c9c6c33844050a93661640fda38e0567d2826b50df"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed69af4fe2a0949b1ea1d012bf065c77b4c7822bad4737f17807af2adb15a73c"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e1c18890091aa3cc8a77967943476b729dc2016f4cfe11e45d89b12519d4a93"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:91b8fb9427e33f83ca2ba9501221ffaac1ecf0407f758c4d2f283c523da185ee"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:536a7a8a53b75b2e98ff96edb2dfb91a26b81c4fed82782035767db5a465be46"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a64619a9c47c25582190af38e9eb382279ad42e1f06034f14d794670796016c0"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c73a6bbc97ba1b5a0c3c992ae93d721c395bdbb120492759b94cc1ac71bc6350"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a173401d7821a2a81c7b47d4e7d5c4021375a1441af0c58611c1957445055056"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7520e799b1f84e095cce919bd6c23c9d49472deeef25fe1ef960b04cca51c3fc"}, + {file = "yarl-1.18.0-cp311-cp311-win32.whl", hash = "sha256:c4cb992d8090d5ae5f7afa6754d7211c578be0c45f54d3d94f7781c495d56716"}, + {file = "yarl-1.18.0-cp311-cp311-win_amd64.whl", hash = "sha256:52c136f348605974c9b1c878addd6b7a60e3bf2245833e370862009b86fa4689"}, + {file = "yarl-1.18.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1ece25e2251c28bab737bdf0519c88189b3dd9492dc086a1d77336d940c28ced"}, + {file = "yarl-1.18.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:454902dc1830d935c90b5b53c863ba2a98dcde0fbaa31ca2ed1ad33b2a7171c6"}, + {file = "yarl-1.18.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01be8688fc211dc237e628fcc209dda412d35de7642453059a0553747018d075"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d26f1fa9fa2167bb238f6f4b20218eb4e88dd3ef21bb8f97439fa6b5313e30d"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b234a4a9248a9f000b7a5dfe84b8cb6210ee5120ae70eb72a4dcbdb4c528f72f"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe94d1de77c4cd8caff1bd5480e22342dbd54c93929f5943495d9c1e8abe9f42"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b4c90c5363c6b0a54188122b61edb919c2cd1119684999d08cd5e538813a28e"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a98ecadc5a241c9ba06de08127ee4796e1009555efd791bac514207862b43d"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9106025c7f261f9f5144f9aa7681d43867eed06349a7cfb297a1bc804de2f0d1"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f275ede6199d0f1ed4ea5d55a7b7573ccd40d97aee7808559e1298fe6efc8dbd"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f7edeb1dcc7f50a2c8e08b9dc13a413903b7817e72273f00878cb70e766bdb3b"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c083f6dd6951b86e484ebfc9c3524b49bcaa9c420cb4b2a78ef9f7a512bfcc85"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:80741ec5b471fbdfb997821b2842c59660a1c930ceb42f8a84ba8ca0f25a66aa"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b1a3297b9cad594e1ff0c040d2881d7d3a74124a3c73e00c3c71526a1234a9f7"}, + {file = "yarl-1.18.0-cp312-cp312-win32.whl", hash = "sha256:cd6ab7d6776c186f544f893b45ee0c883542b35e8a493db74665d2e594d3ca75"}, + {file = "yarl-1.18.0-cp312-cp312-win_amd64.whl", hash = "sha256:039c299a0864d1f43c3e31570045635034ea7021db41bf4842693a72aca8df3a"}, + {file = "yarl-1.18.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6fb64dd45453225f57d82c4764818d7a205ee31ce193e9f0086e493916bd4f72"}, + {file = "yarl-1.18.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3adaaf9c6b1b4fc258584f4443f24d775a2086aee82d1387e48a8b4f3d6aecf6"}, + {file = "yarl-1.18.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:da206d1ec78438a563c5429ab808a2b23ad7bc025c8adbf08540dde202be37d5"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:576d258b21c1db4c6449b1c572c75d03f16a482eb380be8003682bdbe7db2f28"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c60e547c0a375c4bfcdd60eef82e7e0e8698bf84c239d715f5c1278a73050393"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3818eabaefb90adeb5e0f62f047310079d426387991106d4fbf3519eec7d90a"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5f72421246c21af6a92fbc8c13b6d4c5427dfd949049b937c3b731f2f9076bd"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7fa7d37f2ada0f42e0723632993ed422f2a679af0e200874d9d861720a54f53e"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:42ba84e2ac26a3f252715f8ec17e6fdc0cbf95b9617c5367579fafcd7fba50eb"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6a49ad0102c0f0ba839628d0bf45973c86ce7b590cdedf7540d5b1833ddc6f00"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:96404e8d5e1bbe36bdaa84ef89dc36f0e75939e060ca5cd45451aba01db02902"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a0509475d714df8f6d498935b3f307cd122c4ca76f7d426c7e1bb791bcd87eda"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1ff116f0285b5c8b3b9a2680aeca29a858b3b9e0402fc79fd850b32c2bcb9f8b"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2580c1d7e66e6d29d6e11855e3b1c6381971e0edd9a5066e6c14d79bc8967af"}, + {file = "yarl-1.18.0-cp313-cp313-win32.whl", hash = "sha256:14408cc4d34e202caba7b5ac9cc84700e3421a9e2d1b157d744d101b061a4a88"}, + {file = "yarl-1.18.0-cp313-cp313-win_amd64.whl", hash = "sha256:1db1537e9cb846eb0ff206eac667f627794be8b71368c1ab3207ec7b6f8c5afc"}, + {file = "yarl-1.18.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fa2c9cb607e0f660d48c54a63de7a9b36fef62f6b8bd50ff592ce1137e73ac7d"}, + {file = "yarl-1.18.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c0f4808644baf0a434a3442df5e0bedf8d05208f0719cedcd499e168b23bfdc4"}, + {file = "yarl-1.18.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7db9584235895a1dffca17e1c634b13870852094f6389b68dcc6338086aa7b08"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:309f8d27d6f93ceeeb80aa6980e883aa57895270f7f41842b92247e65d7aeddf"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:609ffd44fed2ed88d9b4ef62ee860cf86446cf066333ad4ce4123505b819e581"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f172b8b2c72a13a06ea49225a9c47079549036ad1b34afa12d5491b881f5b993"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d89ae7de94631b60d468412c18290d358a9d805182373d804ec839978b120422"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:466d31fd043ef9af822ee3f1df8fdff4e8c199a7f4012c2642006af240eade17"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7609b8462351c4836b3edce4201acb6dd46187b207c589b30a87ffd1813b48dc"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:d9d4f5e471e8dc49b593a80766c2328257e405f943c56a3dc985c125732bc4cf"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:67b336c15e564d76869c9a21316f90edf546809a5796a083b8f57c845056bc01"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b212452b80cae26cb767aa045b051740e464c5129b7bd739c58fbb7deb339e7b"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:38b39b7b3e692b6c92b986b00137a3891eddb66311b229d1940dcbd4f025083c"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a7ee6884a8848792d58b854946b685521f41d8871afa65e0d4a774954e9c9e89"}, + {file = "yarl-1.18.0-cp39-cp39-win32.whl", hash = "sha256:b4095c5019bb889aa866bf12ed4c85c0daea5aafcb7c20d1519f02a1e738f07f"}, + {file = "yarl-1.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:2d90f2e4d16a5b0915ee065218b435d2ef619dd228973b1b47d262a6f7cd8fa5"}, + {file = "yarl-1.18.0-py3-none-any.whl", hash = "sha256:dbf53db46f7cf176ee01d8d98c39381440776fcda13779d269a8ba664f69bec0"}, + {file = "yarl-1.18.0.tar.gz", hash = "sha256:20d95535e7d833889982bfe7cc321b7f63bf8879788fee982c76ae2b24cfb715"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" +propcache = ">=0.2.0" + +[metadata] +lock-version = "2.0" +python-versions = "^3.12" +content-hash = "78a01182417e4bed52971d7e8cd7dbf3a74c69c5b3c191c77b022fb7bd0be165" diff --git a/backend/src/poetry.toml b/backend/poetry.toml similarity index 100% rename from backend/src/poetry.toml rename to backend/poetry.toml diff --git a/backend/src/pyproject.toml b/backend/pyproject.toml similarity index 86% rename from backend/src/pyproject.toml rename to backend/pyproject.toml index e82d0429b..ba44ea2f3 100644 --- a/backend/src/pyproject.toml +++ b/backend/pyproject.toml @@ -19,7 +19,7 @@ pyjwt = "^2.7.0" typer = {extras = ["all"], version = "^0.9.0"} asyncmy = "^0.2.8" cryptography = "^42.0.2" -markdown = "3.5.2" +markdown = "3.7" pydantic= "2.6.3" redis = "^5.0.1" inject = "^5.2.0" @@ -33,8 +33,8 @@ optional = true [tool.poetry.group.dev.dependencies] pytest = "^8.1.1" black = {extras = ["d"], version = "^24.3.0"} -mypy = "^1.9.0" -ruff = "~0.3.4" +mypy = "^1.10.0" +ruff = "^0.7.3" pytest-sugar = "^1.0.0" httpx = "^0.26.0" pytest-asyncio = "^0.21.1" @@ -47,12 +47,13 @@ deepdiff = "^6.7.1" optional = true [tool.poetry.group.docs.dependencies] -mkdocs = "^1.4.3" -mkdocstrings = "^0.24.0" -mkdocs-material = "^9.1.19" -mkdocs-monorepo-plugin = "^1.0.5" -mkdocstrings-python = "^1.2.1" -coverage-badge = "^1.1.0" +mkdocs = "^1.6.1" +mkdocstrings = "^0.27.0" +mkdocs-material = "^9.5.44" +mkdocs-monorepo-plugin = "^1.1.0" +mkdocstrings-python = "^1.12.2" +coverage-badge = "^1.1.2" +griffe-fastapi = "0.1.5" [tool.pytest.ini_options] markers = [ @@ -84,12 +85,14 @@ module = "deepdiff.*" ignore_missing_imports = true [tool.ruff] +target-version = "py312" + +[tool.ruff.lint] select = ["E", "W", "F", "C", "B", "D", "I", "N"] fixable = ["I"] ignore = ["D107", "D203", "D213", "D406", "D407", "E501", "N818", "B008"] -target-version = "py310" -[tool.ruff.pydocstyle] +[tool.ruff.lint.pydocstyle] convention = "google" [build-system] diff --git a/backend/src/kwai/__main__.py b/backend/src/kwai/__main__.py new file mode 100644 index 000000000..041a4aa73 --- /dev/null +++ b/backend/src/kwai/__main__.py @@ -0,0 +1,19 @@ +"""Module for starting kwai. + +When this module is used, it will start the api and frontend application. +If only the api is required, use kwai.api. +""" + +import uvicorn + +from kwai.app import APP_NAME +from kwai.core.args import create_args + +args = create_args(APP_NAME) +uvicorn.run( + "kwai.app:create_app", + host=args.host, + port=args.port, + factory=True, + reload=args.reload, +) diff --git a/backend/src/kwai/api/__main__.py b/backend/src/kwai/api/__main__.py index 38d3d7ca5..4141c5e99 100644 --- a/backend/src/kwai/api/__main__.py +++ b/backend/src/kwai/api/__main__.py @@ -1,29 +1,17 @@ -"""Module for starting the api server.""" -import argparse - -import uvicorn +"""Module for starting the api server. +This will only start the api server. Use this when the frontend is not served +by FastAPI or if the api server is running on another server. +""" -def create_args(): - """Parse and create cli arguments.""" - parser = argparse.ArgumentParser(description="kwai backend") - parser.add_argument( - "--reload", - action=argparse.BooleanOptionalAction, - help="Watch for code changes or not", - ) - parser.add_argument( - "--host", type=str, default="0.0.0.0", help="The host of the api server." - ) - parser.add_argument( - "--port", type=int, default=8000, help="The port of the api server." - ) - return parser.parse_args() +import uvicorn +from kwai.api.app import APP_NAME +from kwai.core.args import create_args -args = create_args() +args = create_args(APP_NAME) uvicorn.run( - "kwai.api.app:create_app", + "kwai.api.app.create_api", host=args.host, port=args.port, factory=True, diff --git a/backend/src/kwai/api/app.py b/backend/src/kwai/api/app.py index 9871545ef..cc1dcb01c 100644 --- a/backend/src/kwai/api/app.py +++ b/backend/src/kwai/api/app.py @@ -1,4 +1,5 @@ """Module that implements a factory method for a FastAPI application.""" + import os import sys import uuid @@ -14,16 +15,19 @@ from kwai.api.v1.news.api import api_router as news_api_router from kwai.api.v1.pages.api import api_router as pages_api_router from kwai.api.v1.portal.api import api_router as portal_api_router +from kwai.api.v1.teams.api import router as teams_api_router from kwai.api.v1.trainings.api import api_router as training_api_router from kwai.core.settings import LoggerSettings, Settings, get_settings +APP_NAME = "kwai API" + @asynccontextmanager async def lifespan(app: FastAPI): """Log the start/stop of the application.""" - logger.info("kwai is starting") + logger.info(f"{APP_NAME} is starting") yield - logger.warning("kwai has ended!") + logger.warning(f"{APP_NAME} has ended!") def configure_logger(settings: LoggerSettings): @@ -57,13 +61,13 @@ def log_format(record): ) -def create_app(settings: Settings | None = None) -> FastAPI: +def create_api(settings: Settings | None = None) -> FastAPI: """Create the FastAPI application. Args: settings: Settings to use in this application. """ - app = FastAPI(title="kwai", lifespan=lifespan, separate_input_output_schemas=False) + app = FastAPI(lifespan=lifespan, separate_input_output_schemas=False) if settings is None: settings = get_settings() @@ -110,11 +114,12 @@ async def log(request: Request, call_next): if settings.logger: configure_logger(settings.logger) - app.include_router(auth_api_router, prefix="/api/v1") - app.include_router(portal_api_router, prefix="/api/v1") - app.include_router(pages_api_router, prefix="/api/v1") - app.include_router(news_api_router, prefix="/api/v1") - app.include_router(training_api_router, prefix="/api/v1") - app.include_router(club_api_router, prefix="/api/v1") + app.include_router(auth_api_router, prefix="/v1") + app.include_router(portal_api_router, prefix="/v1") + app.include_router(pages_api_router, prefix="/v1") + app.include_router(news_api_router, prefix="/v1") + app.include_router(teams_api_router, prefix="/v1") + app.include_router(training_api_router, prefix="/v1") + app.include_router(club_api_router, prefix="/v1") return app diff --git a/backend/src/kwai/api/dependencies.py b/backend/src/kwai/api/dependencies.py index 56e523dde..e16f761f5 100644 --- a/backend/src/kwai/api/dependencies.py +++ b/backend/src/kwai/api/dependencies.py @@ -1,9 +1,11 @@ """Module that integrates the dependencies in FastAPI.""" + from typing import AsyncGenerator import jwt from fastapi import Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer +from fastapi.templating import Jinja2Templates from jwt import ExpiredSignatureError from redis.asyncio import Redis @@ -34,6 +36,13 @@ async def create_database( await database.close() +async def create_templates(settings=Depends(get_settings)) -> Jinja2Templates: + """Create the template engine dependency.""" + templates = Jinja2Templates(directory=settings.template.path) + templates.env.add_extension("jinja2.ext.do") + return templates + + async def get_current_user( settings=Depends(get_settings), db=Depends(create_database), diff --git a/backend/src/kwai/api/v1/auth/api.py b/backend/src/kwai/api/v1/auth/api.py index 80301154c..9961336f4 100644 --- a/backend/src/kwai/api/v1/auth/api.py +++ b/backend/src/kwai/api/v1/auth/api.py @@ -1,4 +1,5 @@ """Module that defines the auth apis.""" + from fastapi import APIRouter from kwai.api.v1.auth.endpoints import login, user, user_invitations diff --git a/backend/src/kwai/api/v1/auth/endpoints/login.py b/backend/src/kwai/api/v1/auth/endpoints/login.py index 9d92eefdd..dd2b74e7e 100644 --- a/backend/src/kwai/api/v1/auth/endpoints/login.py +++ b/backend/src/kwai/api/v1/auth/endpoints/login.py @@ -1,7 +1,9 @@ """Module that implements all APIs for login.""" +from typing import Annotated + import jwt -from fastapi import APIRouter, Depends, Form, HTTPException, Response, status +from fastapi import APIRouter, Depends, Form, HTTPException, status from fastapi.security import OAuth2PasswordRequestForm from jwt import ExpiredSignatureError from loguru import logger @@ -71,23 +73,25 @@ class TokenSchema(BaseModel): @router.post( "/login", summary="Create access and refresh token for a user.", + responses={ + 200: {"description": "The user is logged in successfully."}, + 401: { + "description": "The email is invalid, authentication failed or user is unknown." + }, + }, ) async def login( - settings: Settings = Depends(get_settings), - db: Database = Depends(create_database), - form_data: OAuth2PasswordRequestForm = Depends(), + settings: Annotated[Settings, Depends(get_settings)], + db: Annotated[Database, Depends(create_database)], + form_data: Annotated[OAuth2PasswordRequestForm, Depends()], ) -> TokenSchema: """Login a user. - The response is a TokenSchema. - - Note: - This request expects a form (application/x-www-form-urlencoded). + This request expects a form (application/x-www-form-urlencoded). The form + must contain a `username` and `password` field. The username is + the email address of the user. - Args: - settings: Settings dependency - db: Database dependency - form_data: Form data that contains the username and password + The response is a [TokenSchema][kwai.api.v1.auth.endpoints.login.TokenSchema]. """ command = AuthenticateUserCommand( username=form_data.username, @@ -118,27 +122,27 @@ async def login( return _encode_token(refresh_token, settings.security) -@router.post("/logout", summary="Logout the current user") +@router.post( + "/logout", + summary="Logout the current user", + responses={ + 200: {"description": "The user is logged out successfully."}, + 404: {"description": "The token is not found."}, + }, +) async def logout( - settings=Depends(get_settings), - db=Depends(create_database), - user: UserEntity = Depends(get_current_user), - refresh_token: str = Form(), + settings: Annotated[Settings, Depends(get_settings)], + db: Annotated[Database, Depends(create_database)], + user: Annotated[UserEntity, Depends(get_current_user)], # noqa + refresh_token: Annotated[str, Form()], ) -> None: """Log out the current user. A user is logged out by revoking the refresh token. The associated access token will also be revoked. - Args: - settings: Settings dependency - db: Database dependency - user: The currently logged-in user - refresh_token: The active refresh token of the user - - Returns: - Http code 200 on success, 401 when the user is not logged in, - 404 when the refresh token is not found. + This request expects a form (application/x-www-form-urlencoded). The form + must contain a **refresh_token** field. """ decoded_refresh_token = jwt.decode( refresh_token, @@ -160,21 +164,24 @@ async def logout( @router.post( "/access_token", summary="Renew an access token using a refresh token.", + responses={ + 200: {"description": "The access token is renewed."}, + 401: {"description": "The refresh token is expired."}, + }, ) async def renew_access_token( - settings=Depends(get_settings), - db=Depends(create_database), - refresh_token: str = Form(), + settings: Annotated[Settings, Depends(get_settings)], + db: Annotated[Database, Depends(create_database)], + refresh_token: Annotated[str, Form()], ) -> TokenSchema: """Refresh the access token. - Args: - settings(Settings): Settings dependency - db(Database): Database dependency - refresh_token(str): The active refresh token of the user + The response is a [TokenSchema][kwai.api.v1.auth.endpoints.login.TokenSchema]. - Returns: - TokenSchema: On success a new TokenSchema is returned. + When the refresh token is expired, the user needs to log in again. + + This request expects a form (application/x-www-form-urlencoded). The form + must contain a **refresh_token** field. """ try: decoded_refresh_token = jwt.decode( @@ -208,25 +215,24 @@ async def renew_access_token( @router.post( "/recover", summary="Initiate a password reset flow", - status_code=status.HTTP_200_OK, - response_class=Response, + responses={ + 200: {"description": "Ok."}, + }, ) async def recover_user( - email: str = Form(), - db=Depends(create_database), - publisher: Publisher = Depends(get_publisher), + db: Annotated[Database, Depends(create_database)], + publisher: Annotated[Publisher, Depends(get_publisher)], + email: Annotated[str, Form()], ) -> None: """Start a recover password flow for the given email address. A mail with a unique id will be sent using the message bus. - Note: - To avoid leaking information, this api will always respond with 200 + This request expects a form (application/x-www-form-urlencoded). The form + must contain an **email** field. - Args: - email(str): The email of the user that wants to reset the password. - db(Database): Database dependency - publisher(Publisher): A publisher to publish the event + !!! Note + To avoid leaking information, this api will always respond with 200 """ command = RecoverUserCommand(email=email) try: @@ -242,19 +248,26 @@ async def recover_user( @router.post( "/reset", summary="Reset the password of a user.", - status_code=status.HTTP_200_OK, + responses={ # noqa B006 + 200: {"description": "The password is reset successfully."}, + 403: {"description": "This request is forbidden."}, + 404: {"description": "The uniqued id of the recovery could not be found."}, + 422: {"description": "The user could not be found."}, + }, ) -async def reset_password(uuid=Form(), password=Form(), db=Depends(create_database)): +async def reset_password( + uuid: Annotated[str, Form()], + password: Annotated[str, Form()], + db: Annotated[Database, Depends(create_database)], +): """Reset the password of the user. - Args: - uuid(str): The unique id of the password recovery. - password(str): The new password - db(Database): Database dependency + Http code 200 on success, 404 when the unique is invalid, 422 when the + request can't be processed, 403 when the request is forbidden. - Returns: - Http code 200 on success, 404 when the unique is invalid, 422 when the - request can't be processed, 403 when the request is forbidden. + This request expects a form (application/x-www-form-urlencoded). The form + must contain an **uuid** and **password** field. The unique id must be still valid + and is retrieved by [/api/v1/auth/recover][post_/recover]. """ command = ResetPasswordCommand(uuid=uuid, password=password) try: @@ -286,7 +299,7 @@ def _encode_token( access_token=jwt.encode( { "iat": refresh_token.access_token.traceable_time.created_at.timestamp, - "exp": refresh_token.access_token.expiration, + "exp": refresh_token.access_token.expiration.timestamp, "jti": str(refresh_token.access_token.identifier), "sub": str(refresh_token.access_token.user_account.user.uuid), "scope": [], @@ -297,11 +310,11 @@ def _encode_token( refresh_token=jwt.encode( { "iat": refresh_token.traceable_time.created_at.timestamp, - "exp": refresh_token.expiration, + "exp": refresh_token.expiration.timestamp, "jti": str(refresh_token.identifier), }, settings.jwt_refresh_secret, settings.jwt_algorithm, ), - expiration=refresh_token.access_token.expiration.isoformat(" ", "seconds"), + expiration=str(refresh_token.access_token.expiration), ) diff --git a/backend/src/kwai/api/v1/auth/endpoints/user.py b/backend/src/kwai/api/v1/auth/endpoints/user.py index 3ab352268..218486abc 100644 --- a/backend/src/kwai/api/v1/auth/endpoints/user.py +++ b/backend/src/kwai/api/v1/auth/endpoints/user.py @@ -8,7 +8,14 @@ router = APIRouter() -@router.get("/user") +@router.get( + "/user", + summary="Get the id of the current user", + responses={ + 200: {"description": "Ok."}, + 401: {"description": "Not authorized"}, + }, +) def get(user: UserEntity = Depends(get_current_user)): """Get the current user.""" return {"id": str(user.uuid)} diff --git a/backend/src/kwai/api/v1/auth/endpoints/user_invitations.py b/backend/src/kwai/api/v1/auth/endpoints/user_invitations.py index a9f8cb0ec..86de5b986 100644 --- a/backend/src/kwai/api/v1/auth/endpoints/user_invitations.py +++ b/backend/src/kwai/api/v1/auth/endpoints/user_invitations.py @@ -1,6 +1,6 @@ """Module that implements invitations endpoints.""" -from fastapi import APIRouter, Depends, HTTPException, Response, status +from fastapi import APIRouter, Depends, HTTPException, status from loguru import logger from kwai.api.dependencies import create_database, get_current_user, get_publisher @@ -30,14 +30,27 @@ router = APIRouter() -@router.post("/invitations") +@router.post( + "/invitations", + summary="Create a user invitation", + status_code=status.HTTP_201_CREATED, + responses={ + 201: {"description": "User invitation is created"}, + 401: {"description": "Not authorized."}, + 422: {"description": "User invitation could not be created"}, + }, +) async def create_user_invitation( user_invitation_document: UserInvitationDocument, db=Depends(create_database), user: UserEntity = Depends(get_current_user), publisher=Depends(get_publisher), ) -> UserInvitationDocument: - """Create a user invitation.""" + """Create a user invitation. + + A wrong email address or a still pending user invitation will result in a 422 + status code. + """ command = InviteUserCommand( first_name=user_invitation_document.resource.attributes.first_name, last_name=user_invitation_document.resource.attributes.last_name, @@ -67,13 +80,18 @@ async def create_user_invitation( "/invitations/{uuid}", summary="Delete a user invitation", status_code=status.HTTP_200_OK, - response_class=Response, + responses={ + 200: {"description": "User invitation is deleted."}, + 401: {"description": "Not authorized."}, + 404: {"description": "User invitation does not exist."}, + 422: {"description": "Invalid unique id passed for the user invitation."}, + }, ) async def delete_user_invitation( uuid: str, db=Depends(create_database), user: UserEntity = Depends(get_current_user), -): +) -> None: """Delete the user invitation with the given unique id.""" command = DeleteUserInvitationCommand(uuid=uuid) try: @@ -88,13 +106,23 @@ async def delete_user_invitation( ) from ex -@router.get("/invitations") +@router.get( + "/invitations", + summary="Get a list of user invitations", + responses={ + 200: {"description": "Ok."}, + 401: {"description": "Not authorized."}, + }, +) async def get_user_invitations( pagination: PaginationModel = Depends(PaginationModel), db=Depends(create_database), user: UserEntity = Depends(get_current_user), ) -> UserInvitationDocument: - """Get all user invitations.""" + """Get all user invitations. + + Use the page[offset] and page[limit] query parameters to get a paginated result. + """ command = GetInvitationsCommand(offset=pagination.offset, limit=pagination.limit) count, invitation_iterator = await GetInvitations( UserInvitationDbRepository(db) @@ -111,7 +139,11 @@ async def get_user_invitations( return result -@router.get("/invitations/{uuid}") +@router.get( + "/invitations/{uuid}", + summary="Get a user invitation", + responses={200: {"description": "Ok."}, 401: {"description": "Not authorized."}}, +) async def get_user_invitation( uuid: str, db=Depends(create_database), diff --git a/backend/src/kwai/api/v1/club/endpoints/members.py b/backend/src/kwai/api/v1/club/endpoints/members.py index 3c29fa974..f573eea36 100644 --- a/backend/src/kwai/api/v1/club/endpoints/members.py +++ b/backend/src/kwai/api/v1/club/endpoints/members.py @@ -4,13 +4,14 @@ from pydantic import BaseModel, Field from kwai.api.dependencies import create_database, get_current_user +from kwai.api.v1.club.presenters import JsonApiMemberPresenter, JsonApiMembersPresenter from kwai.api.v1.club.schemas.member import MemberDocument -from kwai.core.json_api import Meta, PaginationModel +from kwai.core.json_api import PaginationModel from kwai.modules.club.get_member import GetMember, GetMemberCommand from kwai.modules.club.get_members import GetMembers, GetMembersCommand -from kwai.modules.club.members.member_db_repository import MemberDbRepository -from kwai.modules.club.members.member_repository import MemberNotFoundException -from tests.core.domain.test_entity import UserEntity +from kwai.modules.club.repositories.member_db_repository import MemberDbRepository +from kwai.modules.club.repositories.member_repository import MemberNotFoundException +from kwai.modules.identity.users.user import UserEntity router = APIRouter() @@ -38,15 +39,10 @@ async def get_members( license_end_year=members_filter.license_end_year, license_end_month=members_filter.license_end_month, ) - count, member_iterator = await GetMembers(MemberDbRepository(db)).execute(command) - result = MemberDocument( - meta=Meta(count=count, offset=command.offset, limit=command.limit), data=[] - ) - async for member in member_iterator: - member_document = MemberDocument.create(member) - result.merge(member_document) + presenter = JsonApiMembersPresenter() + await GetMembers(MemberDbRepository(db), presenter).execute(command) - return result + return presenter.get_document() @router.get("/members/{uuid}") @@ -58,11 +54,12 @@ async def get_member( """Get a member with the given unique id.""" command = GetMemberCommand(uuid=uuid) + presenter = JsonApiMemberPresenter() try: - member = await GetMember(MemberDbRepository(db)).execute(command) + await GetMember(MemberDbRepository(db), presenter).execute(command) except MemberNotFoundException as ex: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=str(ex) ) from ex - return MemberDocument.create(member) + return presenter.get_document() diff --git a/backend/src/kwai/api/v1/club/endpoints/upload_members.py b/backend/src/kwai/api/v1/club/endpoints/upload_members.py index 3c8a50bad..0fbe69a7e 100644 --- a/backend/src/kwai/api/v1/club/endpoints/upload_members.py +++ b/backend/src/kwai/api/v1/club/endpoints/upload_members.py @@ -3,26 +3,26 @@ from pathlib import Path from typing import Annotated -from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status +from fastapi import APIRouter, Depends, File, HTTPException, Query, UploadFile, status from pydantic import BaseModel, Field from kwai.api.dependencies import create_database, get_current_user +from kwai.api.v1.club.presenters import JsonApiUploadMemberPresenter from kwai.api.v1.club.schemas.member import MemberDocument from kwai.core.db.database import Database from kwai.core.db.uow import UnitOfWork from kwai.core.functions import generate_filenames -from kwai.core.json_api import Meta from kwai.core.settings import Settings, get_settings from kwai.modules.club.import_members import ( - FailureResult, ImportMembers, ImportMembersCommand, - OkResult, ) -from kwai.modules.club.members.country_db_repository import CountryDbRepository -from kwai.modules.club.members.file_upload_db_repository import FileUploadDbRepository -from kwai.modules.club.members.flemish_member_importer import FlemishMemberImporter -from kwai.modules.club.members.member_db_repository import MemberDbRepository +from kwai.modules.club.repositories.country_db_repository import CountryDbRepository +from kwai.modules.club.repositories.file_upload_db_repository import ( + FileUploadDbRepository, +) +from kwai.modules.club.repositories.flemish_member_importer import FlemishMemberImporter +from kwai.modules.club.repositories.member_db_repository import MemberDbRepository from kwai.modules.identity.users.user import UserEntity router = APIRouter() @@ -54,6 +54,7 @@ async def upload( settings: Annotated[Settings, Depends(get_settings)], database: Annotated[Database, Depends(create_database)], user: Annotated[UserEntity, Depends(get_current_user)], + preview: Annotated[bool, Query(description="Whether or not to preview")] = True, ) -> MemberDocument: """Upload a members csv file.""" if member_file.filename is None: @@ -70,8 +71,9 @@ async def upload( detail=f"Failed to upload members file: {ex}", ) from ex + presenter = JsonApiUploadMemberPresenter() async with UnitOfWork(database): - imported_member_generator = ImportMembers( + await ImportMembers( FlemishMemberImporter( str(member_filename), user.create_owner(), @@ -79,43 +81,9 @@ async def upload( ), FileUploadDbRepository(database), MemberDbRepository(database), - ).execute(ImportMembersCommand()) - - meta = Meta(count=0, offset=0, limit=0, errors=[]) - response = MemberDocument(meta=meta, data=[]) - upload_entity = None - async for result in imported_member_generator: - if upload_entity is None: - upload_entity = result.file_upload - - match result: - case OkResult(): - member_document = MemberDocument.create(result.member) - member_document.resource.meta.row = result.row - member_document.resource.meta.new = not result.member.has_id() - # A new member has related resources that are not saved yet, - # so give them temporarily the same id as the member. - if member_document.resource.meta.new: - member_document.resource.relationships.person.data.id = ( - member_document.resource.id - ) - for included in member_document.included: - if included.type == "persons": - included.relationships.contact.data.id = ( - member_document.resource.id - ) - if included.id == "0": - included.id = member_document.resource.id - meta.count += 1 - response.merge(member_document) - case FailureResult(): - meta.errors.append({"row": result.row, "message": result.to_message()}) - case _: - raise HTTPException( - status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, - detail="Unexpected result returned", - ) - return response + presenter, + ).execute(ImportMembersCommand(preview=preview)) + return presenter.get_document() async def upload_file(uploaded_file, path: str): diff --git a/backend/src/kwai/api/v1/club/presenters.py b/backend/src/kwai/api/v1/club/presenters.py new file mode 100644 index 000000000..ba0025d10 --- /dev/null +++ b/backend/src/kwai/api/v1/club/presenters.py @@ -0,0 +1,74 @@ +"""Module that defines presenters for the club api.""" + +from kwai.api.v1.club.schemas.member import MemberDocument +from kwai.core.domain.presenter import AsyncPresenter, IterableResult, Presenter +from kwai.core.json_api import Error, ErrorSource, JsonApiPresenter, Meta +from kwai.modules.club.domain.member import MemberEntity +from kwai.modules.club.import_members import ( + FailureMemberImportResult, + MemberImportResult, + OkMemberImportResult, +) + + +class JsonApiMemberPresenter(JsonApiPresenter[MemberDocument], Presenter[MemberEntity]): + """A presenter that transform a member entity into a JSON:API document.""" + + def present(self, member: MemberEntity) -> None: + self._document = MemberDocument.create(member) + + +class JsonApiMembersPresenter( + JsonApiPresenter[MemberDocument], AsyncPresenter[IterableResult[MemberEntity]] +): + """A presenter that transform an iterator for members into a JSON:API document.""" + + async def present(self, result: IterableResult[MemberEntity]) -> None: + self._document = MemberDocument( + meta=Meta(count=result.count, offset=result.offset, limit=result.limit), + data=[], + ) + async for member in result.iterator: + member_document = MemberDocument.create(member) + self._document.merge(member_document) + + +class JsonApiUploadMemberPresenter( + JsonApiPresenter[MemberDocument], Presenter[MemberImportResult] +): + """A presenter that transform a file upload of a member into a JSON:API document.""" + + def __init__(self) -> None: + super().__init__() + self._document = MemberDocument( + meta=Meta(count=0, offset=0, limit=0), data=[], errors=[] + ) + + def present(self, result: MemberImportResult) -> None: + match result: + case OkMemberImportResult(): + member_document = MemberDocument.create(result.member) + member_document.resource.meta.row = result.row + member_document.resource.meta.new = not result.member.has_id() + # A new member has related resources that are not saved yet, + # so give them temporarily the same id as the member. + if member_document.resource.meta.new: + member_document.resource.relationships.person.data.id = ( + member_document.resource.id + ) + for included in member_document.included: + if included.type == "persons": + included.relationships.contact.data.id = ( + member_document.resource.id + ) + if included.id == "0": + included.id = member_document.resource.id + self._document.meta.count += 1 + self._document.merge(member_document) + case FailureMemberImportResult(): + self._document.errors.append( + Error( + source=ErrorSource(pointer=str(result.row)), + detail=result.to_message(), + ) + ) diff --git a/backend/src/kwai/api/v1/club/schemas/contact.py b/backend/src/kwai/api/v1/club/schemas/contact.py index 2092707cb..60cee1d94 100644 --- a/backend/src/kwai/api/v1/club/schemas/contact.py +++ b/backend/src/kwai/api/v1/club/schemas/contact.py @@ -4,16 +4,13 @@ from pydantic import BaseModel, Field -from kwai.api.v1.club.schemas.country import ( - CountryDocument, - CountryResource, -) from kwai.api.v1.club.schemas.resources import ( ContactResourceIdentifier, - CountryResourceIdentifier, ) +from kwai.api.v1.resources import CountryResourceIdentifier +from kwai.api.v1.schemas import CountryDocument, CountryResource from kwai.core.json_api import Document, Relationship, ResourceData, ResourceMeta -from kwai.modules.club.members.contact import ContactEntity +from kwai.modules.club.domain.contact import ContactEntity class ContactAttributes(BaseModel): diff --git a/backend/src/kwai/api/v1/club/schemas/member.py b/backend/src/kwai/api/v1/club/schemas/member.py index 28f681225..d9cf468fb 100644 --- a/backend/src/kwai/api/v1/club/schemas/member.py +++ b/backend/src/kwai/api/v1/club/schemas/member.py @@ -5,7 +5,6 @@ from pydantic import BaseModel, Field from kwai.api.v1.club.schemas.contact import ContactResource -from kwai.api.v1.club.schemas.country import CountryResource from kwai.api.v1.club.schemas.person import ( PersonDocument, PersonResource, @@ -14,8 +13,9 @@ MemberResourceIdentifier, PersonResourceIdentifier, ) +from kwai.api.v1.schemas import CountryResource from kwai.core.json_api import Document, Relationship, ResourceData, ResourceMeta -from kwai.modules.club.members.member import MemberEntity +from kwai.modules.club.domain.member import MemberEntity class MemberAttributes(BaseModel): diff --git a/backend/src/kwai/api/v1/club/schemas/person.py b/backend/src/kwai/api/v1/club/schemas/person.py index aa15daf76..dc9acaa32 100644 --- a/backend/src/kwai/api/v1/club/schemas/person.py +++ b/backend/src/kwai/api/v1/club/schemas/person.py @@ -5,14 +5,14 @@ from pydantic import BaseModel, Field from kwai.api.v1.club.schemas.contact import ContactDocument, ContactResource -from kwai.api.v1.club.schemas.country import CountryDocument, CountryResource from kwai.api.v1.club.schemas.resources import ( ContactResourceIdentifier, - CountryResourceIdentifier, PersonResourceIdentifier, ) +from kwai.api.v1.resources import CountryResourceIdentifier +from kwai.api.v1.schemas import CountryDocument, CountryResource from kwai.core.json_api import Document, Relationship, ResourceData, ResourceMeta -from kwai.modules.club.members.person import PersonEntity +from kwai.modules.club.domain.person import PersonEntity class PersonAttributes(BaseModel): diff --git a/backend/src/kwai/api/v1/club/schemas/resources.py b/backend/src/kwai/api/v1/club/schemas/resources.py index c179e8df7..2f3464c24 100644 --- a/backend/src/kwai/api/v1/club/schemas/resources.py +++ b/backend/src/kwai/api/v1/club/schemas/resources.py @@ -23,7 +23,7 @@ class ContactResourceIdentifier(ResourceIdentifier): type: Literal["contacts"] = "contacts" -class CountryResourceIdentifier(ResourceIdentifier): - """A JSON:API resource identifier for a country.""" +class UploadResourceIdentifier(ResourceIdentifier): + """A JSON:API resource identifier for a upload.""" - type: Literal["countries"] = "countries" + type: Literal["uploads"] = "uploads" diff --git a/backend/src/kwai/api/v1/club/schemas/upload.py b/backend/src/kwai/api/v1/club/schemas/upload.py new file mode 100644 index 000000000..3504fd8da --- /dev/null +++ b/backend/src/kwai/api/v1/club/schemas/upload.py @@ -0,0 +1,46 @@ +"""Module for defining the JSON:API resource for an upload.""" + +from types import NoneType +from typing import Self + +from pydantic import BaseModel + +from kwai.api.v1.club.schemas.resources import ( + UploadResourceIdentifier, +) +from kwai.core.json_api import Document, ResourceData, ResourceMeta +from kwai.modules.club.domain.file_upload import FileUploadEntity + + +class UploadAttributes(BaseModel): + """Attributes for the upload JSON:API resource.""" + + filename: str + remark: str + preview: bool + + +class UploadResource( + UploadResourceIdentifier, ResourceData[UploadAttributes, NoneType] +): + """A JSON:API resource for an upload.""" + + +class UploadDocument(Document[UploadResource, NoneType]): + """A JSON:API document for an upload.""" + + @classmethod + def create(cls, upload: FileUploadEntity) -> Self: + """Create a document for an upload.""" + upload_resource = UploadResource( + id=str(upload.uuid), + attributes=UploadAttributes( + filename=upload.filename, remark=upload.remark, preview=upload.preview + ), + meta=ResourceMeta( + created_at=str(upload.traceable_time.created_at), + updated_at=str(upload.traceable_time.updated_at), + ), + ) + + return cls(data=upload_resource) diff --git a/backend/src/kwai/api/v1/portal/endpoints/applications.py b/backend/src/kwai/api/v1/portal/endpoints/applications.py index 15effeeb2..882babc79 100644 --- a/backend/src/kwai/api/v1/portal/endpoints/applications.py +++ b/backend/src/kwai/api/v1/portal/endpoints/applications.py @@ -1,9 +1,11 @@ """Module that implements applications endpoints.""" + from fastapi import APIRouter, Depends, HTTPException, status from kwai.api.dependencies import create_database, get_current_user from kwai.api.schemas.application import ApplicationDocument from kwai.core.json_api import Meta +from kwai.modules.identity.users.user import UserEntity from kwai.modules.portal.applications.application_db_repository import ( ApplicationDbRepository, ) @@ -16,7 +18,6 @@ UpdateApplication, UpdateApplicationCommand, ) -from tests.core.domain.test_entity import UserEntity router = APIRouter() diff --git a/backend/src/kwai/api/v1/resources.py b/backend/src/kwai/api/v1/resources.py new file mode 100644 index 000000000..9ecb7e4ff --- /dev/null +++ b/backend/src/kwai/api/v1/resources.py @@ -0,0 +1,11 @@ +"""Module that defines common JSON:API resource identifiers.""" + +from typing import Literal + +from kwai.core.json_api import ResourceIdentifier + + +class CountryResourceIdentifier(ResourceIdentifier): + """A JSON:API resource identifier for a country.""" + + type: Literal["countries"] = "countries" diff --git a/backend/src/kwai/api/v1/club/schemas/country.py b/backend/src/kwai/api/v1/schemas.py similarity index 82% rename from backend/src/kwai/api/v1/club/schemas/country.py rename to backend/src/kwai/api/v1/schemas.py index 56ec07e1a..5d7ce22be 100644 --- a/backend/src/kwai/api/v1/club/schemas/country.py +++ b/backend/src/kwai/api/v1/schemas.py @@ -1,12 +1,12 @@ -"""Module for defining the JSON:API resource for a country.""" +"""Module for defining common JSON:API schemas.""" from typing import Self from pydantic import BaseModel -from kwai.api.v1.club.schemas.resources import CountryResourceIdentifier +from kwai.api.v1.resources import CountryResourceIdentifier from kwai.core.json_api import Document, ResourceData -from kwai.modules.club.members.country import CountryEntity +from kwai.modules.club.domain.country import CountryEntity class CountryAttributes(BaseModel): diff --git a/backend/src/kwai/api/v1/teams/__init__.py b/backend/src/kwai/api/v1/teams/__init__.py new file mode 100644 index 000000000..52f3e4a9b --- /dev/null +++ b/backend/src/kwai/api/v1/teams/__init__.py @@ -0,0 +1 @@ +"""Package for the teams API.""" diff --git a/backend/src/kwai/api/v1/teams/api.py b/backend/src/kwai/api/v1/teams/api.py new file mode 100644 index 000000000..a4d5fae80 --- /dev/null +++ b/backend/src/kwai/api/v1/teams/api.py @@ -0,0 +1,221 @@ +"""Module that defines the teams API.""" + +from typing import Annotated + +from fastapi import APIRouter, Depends, HTTPException, Query, status +from pydantic import BaseModel, Field + +from kwai.api.dependencies import create_database, get_current_user +from kwai.api.v1.teams.presenters import ( + JsonApiMembersPresenter, + JsonApiTeamMemberPresenter, + JsonApiTeamMembersPresenter, + JsonApiTeamPresenter, + JsonApiTeamsPresenter, +) +from kwai.api.v1.teams.schemas import TeamDocument, TeamMemberDocument +from kwai.core.db.database import Database +from kwai.core.db.uow import UnitOfWork +from kwai.core.json_api import PaginationModel +from kwai.modules.identity.users.user import UserEntity +from kwai.modules.teams.create_team import CreateTeam, CreateTeamCommand +from kwai.modules.teams.create_team_member import ( + CreateTeamMember, + CreateTeamMemberCommand, +) +from kwai.modules.teams.delete_team import DeleteTeam, DeleteTeamCommand +from kwai.modules.teams.domain.team import TeamMemberAlreadyExistException +from kwai.modules.teams.get_members import GetMembers, GetMembersCommand +from kwai.modules.teams.get_team import GetTeam, GetTeamCommand +from kwai.modules.teams.get_teams import GetTeams, GetTeamsCommand +from kwai.modules.teams.repositories.member_db_repository import MemberDbRepository +from kwai.modules.teams.repositories.member_repository import MemberNotFoundException +from kwai.modules.teams.repositories.team_db_repository import TeamDbRepository +from kwai.modules.teams.update_team import UpdateTeam, UpdateTeamCommand +from kwai.modules.training.teams.team_repository import TeamNotFoundException + +router = APIRouter(tags=["teams"]) + + +@router.get("/teams") +async def get_teams( + database: Annotated[Database, Depends(create_database)], +) -> TeamDocument: + """Get all teams of the club.""" + presenter = JsonApiTeamsPresenter() + command = GetTeamsCommand(offset=0, limit=0) + await GetTeams(TeamDbRepository(database), presenter).execute(command) + return presenter.get_document() + + +class TeamMemberFilterModel(BaseModel): + """Define the JSON:API filter for team members.""" + + team: str | None = Field(Query(default=None, alias="filter[team]")) + + +@router.get("/teams/members") +async def get_members( + database: Annotated[Database, Depends(create_database)], + pagination: Annotated[PaginationModel, Depends(PaginationModel)], + team_filter: Annotated[TeamMemberFilterModel, Depends(TeamMemberFilterModel)], +) -> TeamMemberDocument: + """Get all members that can be part of a team.""" + presenter = JsonApiMembersPresenter() + if team_filter.team is not None: + if ":" in team_filter.team: + operand, team_id = team_filter.team.split(":") + if operand not in ("eq", "noteq"): + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Invalid operand", + ) + if not team_id.isdigit(): + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Invalid team id", + ) + + command = GetMembersCommand( + team_id=int(team_id), + in_team=operand == "eq", + offset=pagination.offset, + limit=pagination.limit, + ) + else: + if team_filter.team.isdigit(): + command = GetMembersCommand( + team_id=int(team_filter.team), + offset=pagination.offset, + limit=pagination.limit, + ) + else: + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, + detail="Invalid team id", + ) + else: + command = GetMembersCommand(offset=pagination.offset, limit=pagination.limit) + await GetMembers(MemberDbRepository(database), presenter).execute(command) + return presenter.get_document() + + +@router.get("/teams/{id}") +async def get_team( + id: int, + database: Annotated[Database, Depends(create_database)], +) -> TeamDocument: + """Get the team with the given id.""" + presenter = JsonApiTeamPresenter() + command = GetTeamCommand(id=id) + await GetTeam(TeamDbRepository(database), presenter).execute(command) + return presenter.get_document() + + +@router.post("/teams", status_code=status.HTTP_201_CREATED) +async def create_team( + resource: TeamDocument, + database: Annotated[Database, Depends(create_database)], + user: Annotated[UserEntity, Depends(get_current_user)], +) -> TeamDocument: + """Create a new team.""" + command = CreateTeamCommand( + name=resource.data.attributes.name, + active=resource.data.attributes.active, + remark=resource.data.attributes.remark, + ) + team_presenter = JsonApiTeamPresenter() + async with UnitOfWork(database): + await CreateTeam(TeamDbRepository(database), team_presenter).execute(command) + return team_presenter.get_document() + + +@router.patch( + "/teams/{id}", + status_code=status.HTTP_200_OK, + responses={status.HTTP_404_NOT_FOUND: {"description": "Team not found"}}, +) +async def update_team( + id: int, + resource: TeamDocument, + database: Annotated[Database, Depends(create_database)], + user: Annotated[UserEntity, Depends(get_current_user)], +) -> TeamDocument: + """Update an existing team.""" + command = UpdateTeamCommand( + id=id, + name=resource.data.attributes.name, + active=resource.data.attributes.active, + remark=resource.data.attributes.remark, + ) + team_presenter = JsonApiTeamPresenter() + async with UnitOfWork(database): + await UpdateTeam(TeamDbRepository(database), team_presenter).execute(command) + return team_presenter.get_document() + + +@router.delete( + "/teams/{id}", + status_code=status.HTTP_200_OK, + responses={status.HTTP_404_NOT_FOUND: {"description": "Team not found"}}, +) +async def delete_team( + id: int, + database: Annotated[Database, Depends(create_database)], + user: Annotated[UserEntity, Depends(get_current_user)], +): + """Delete the team with the given id.""" + command = DeleteTeamCommand(id=id) + + try: + async with UnitOfWork(database): + await DeleteTeam(TeamDbRepository(database)).execute(command) + except TeamNotFoundException as ex: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail=str(ex) + ) from ex + + +@router.get("/teams/{id}/members") +async def get_team_members( + id: int, + database: Annotated[Database, Depends(create_database)], +) -> TeamMemberDocument: + """Get the members of the team with the given id.""" + presenter = JsonApiTeamMembersPresenter() + command = GetTeamCommand(id=id) + await GetTeam(TeamDbRepository(database), presenter).execute(command) + return presenter.get_document() + + +@router.post("/teams/{id}/members", status_code=status.HTTP_201_CREATED) +async def create_team_member( + id: int, + resource: TeamMemberDocument, + database: Annotated[Database, Depends(create_database)], +) -> TeamMemberDocument: + """Add a member to the team with the given id.""" + presenter = JsonApiTeamMemberPresenter() + command = CreateTeamMemberCommand( + team_id=id, + member_id=resource.data.id, + active=resource.data.attributes.active, + ) + try: + async with UnitOfWork(database): + await CreateTeamMember( + TeamDbRepository(database), MemberDbRepository(database), presenter + ).execute(command) + return presenter.get_document() + except TeamNotFoundException as ex: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail=str(ex) + ) from ex + except MemberNotFoundException as ex: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail=str(ex) + ) from ex + except TeamMemberAlreadyExistException as ex: + raise HTTPException( + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(ex) + ) from ex diff --git a/backend/src/kwai/api/v1/teams/presenters.py b/backend/src/kwai/api/v1/teams/presenters.py new file mode 100644 index 000000000..f353b0946 --- /dev/null +++ b/backend/src/kwai/api/v1/teams/presenters.py @@ -0,0 +1,70 @@ +"""Module for defining presenters of the teams api.""" + +from kwai.api.v1.teams.schemas import TeamDocument, TeamMemberDocument +from kwai.core.domain.presenter import AsyncPresenter, IterableResult, Presenter +from kwai.core.json_api import JsonApiPresenter, Meta +from kwai.modules.teams.domain.team import TeamEntity +from kwai.modules.teams.domain.team_member import MemberEntity, TeamMember + + +class JsonApiTeamPresenter(JsonApiPresenter[TeamDocument], Presenter[TeamEntity]): + """A presenter that transform a team entity into a JSON:API document.""" + + def present(self, team: TeamEntity) -> None: + self._document = TeamDocument.create(team) + + +class JsonApiTeamsPresenter( + JsonApiPresenter[TeamDocument], AsyncPresenter[IterableResult[TeamEntity]] +): + """A presenter that transforms an iterator of teams into a JSON:API document.""" + + async def present(self, result: IterableResult[TeamEntity]) -> None: + self._document = TeamDocument( + meta=Meta(count=result.count, offset=result.offset, limit=result.limit), + data=[], + ) + async for team in result.iterator: + team_document = TeamDocument.create(team) + self._document.merge(team_document) + + +class JsonApiMembersPresenter( + JsonApiPresenter[TeamMemberDocument], AsyncPresenter[IterableResult[MemberEntity]] +): + """A presenter that transforms an iterator of members into a TeamMember document.""" + + async def present(self, result: IterableResult[MemberEntity]) -> None: + self._document = TeamMemberDocument( + meta=Meta(count=result.count, offset=result.offset, limit=result.limit), + data=[], + ) + async for member in result.iterator: + team_member_document = TeamMemberDocument.create(TeamMember(member=member)) + self._document.merge(team_member_document) + + +class JsonApiTeamMembersPresenter( + JsonApiPresenter[TeamMemberDocument], Presenter[TeamEntity] +): + """A presenter that transforms team members into a JSON:API document.""" + + def present(self, team: TeamEntity) -> None: + self._document = TeamMemberDocument( + meta=Meta(count=len(team.members)), + data=[], + ) + for member in team.members.values(): + team_member_document = TeamMemberDocument.create(member, team) + self._document.merge(team_member_document) + + +class JsonApiTeamMemberPresenter( + JsonApiPresenter[TeamMemberDocument], Presenter[tuple[TeamMember, TeamEntity]] +): + """A presenter that transforms a team member into a JSON:API document.""" + + def present(self, use_case_result: tuple[TeamMember, TeamEntity]) -> None: + self._document = TeamMemberDocument.create( + use_case_result[0], use_case_result[1] + ) diff --git a/backend/src/kwai/api/v1/teams/resources.py b/backend/src/kwai/api/v1/teams/resources.py new file mode 100644 index 000000000..69814d28f --- /dev/null +++ b/backend/src/kwai/api/v1/teams/resources.py @@ -0,0 +1,11 @@ +"""Module that defines all JSON:API resource identifiers for the team API.""" + +from typing import Literal + +from kwai.core.json_api import ResourceIdentifier + + +class TeamMemberResourceIdentifier(ResourceIdentifier): + """A JSON:API resource identifier for a team member.""" + + type: Literal["team_members"] = "team_members" diff --git a/backend/src/kwai/api/v1/teams/schemas.py b/backend/src/kwai/api/v1/teams/schemas.py new file mode 100644 index 000000000..b496dc23a --- /dev/null +++ b/backend/src/kwai/api/v1/teams/schemas.py @@ -0,0 +1,137 @@ +"""Module that defines the schemas for the teams API.""" + +from typing import Annotated, Self + +from pydantic import BaseModel, Field + +from kwai.api.schemas.resources import TeamResourceIdentifier +from kwai.api.v1.resources import CountryResourceIdentifier +from kwai.api.v1.schemas import CountryDocument, CountryResource +from kwai.api.v1.teams.resources import TeamMemberResourceIdentifier +from kwai.core.json_api import Document, Relationship, ResourceData, ResourceMeta +from kwai.modules.teams.domain.team import TeamEntity +from kwai.modules.teams.domain.team_member import TeamMember + + +class TeamMemberAttributes(BaseModel): + """Attributes for a team member.""" + + active: bool + first_name: str + last_name: str + license_number: str + license_end_date: str + gender: int + birthdate: str + active_in_club: bool + + +class TeamMemberRelationships(BaseModel): + """Relationships for a team member JSON:API resource.""" + + nationality: Relationship[CountryResourceIdentifier] + team: Relationship[TeamResourceIdentifier] | None = None + + +class TeamMemberResource( + TeamMemberResourceIdentifier, + ResourceData[TeamMemberAttributes, TeamMemberRelationships], +): + """A JSON:API resource for a team member.""" + + +TeamMemberInclude = Annotated[CountryResource, Field(discriminator="type")] + + +class TeamMemberDocument(Document[TeamMemberResource, TeamMemberInclude]): + """A JSON:API document for one or more team members.""" + + @classmethod + def create(cls, team_member: TeamMember, team: TeamEntity | None = None) -> Self: + """Create a team member document.""" + nationality_document = CountryDocument.create(team_member.member.nationality) + + team_member_resource = TeamMemberResource( + id=str(team_member.member.uuid), + attributes=TeamMemberAttributes( + active=team_member.active, + first_name=team_member.member.name.first_name, + last_name=team_member.member.name.last_name, + license_number=team_member.member.license.number, + license_end_date=str(team_member.member.license.end_date), + gender=team_member.member.gender, + birthdate=str(team_member.member.birthdate), + active_in_club=team_member.member.is_active_in_club, + ), + meta=ResourceMeta( + created_at=str(team_member.traceable_time.created_at), + updated_at=str(team_member.traceable_time.updated_at), + ), + ) + team_member_resource.relationships = TeamMemberRelationships( + nationality=Relationship[CountryResourceIdentifier]( + data=CountryResourceIdentifier(id=nationality_document.resource.id), + ), + team=( + None + if team is None + else Relationship[TeamResourceIdentifier]( + data=TeamResourceIdentifier(id=str(team.id)) + ) + ), + ) + + return cls(data=team_member_resource, included={nationality_document.resource}) + + +class TeamAttributes(BaseModel): + """Attributes for the team JSON:API resource.""" + + name: str + active: bool + remark: str + + +class TeamRelationships(BaseModel): + """Relationships for a team JSON:API resource.""" + + team_members: Relationship[TeamMemberResourceIdentifier] + + +class TeamResource( + TeamResourceIdentifier, ResourceData[TeamAttributes, TeamRelationships] +): + """A JSON:API resource for a team.""" + + +TeamInclude = Annotated[ + TeamMemberResource | CountryResource, Field(discriminator="type") +] + + +class TeamDocument(Document[TeamResource, TeamInclude]): + """A JSON:API document for one or more teams.""" + + @classmethod + def create(cls, team: TeamEntity) -> Self: + """Create a team document from a team entity.""" + team_member_document = TeamMemberDocument(data=[], included=set()) + for team_member in team.members.values(): + team_member_document.merge(TeamMemberDocument.create(team_member)) + + team_resource = TeamResource( + id=str(team.id), + attributes=TeamAttributes( + name=team.name, active=team.is_active, remark=team.remark + ), + relationships=TeamRelationships( + team_members=Relationship[TeamMemberResourceIdentifier]( + data=team_member_document.resources + ) + ), + ) + + included: set[TeamInclude] = set(team_member_document.resources) + included = included.union(team_member_document.included) + + return TeamDocument(data=team_resource, included=included) diff --git a/backend/src/kwai/app.py b/backend/src/kwai/app.py new file mode 100644 index 000000000..c2f10e0aa --- /dev/null +++ b/backend/src/kwai/app.py @@ -0,0 +1,32 @@ +"""Module that creates a FastAPI application for the API and Frontend.""" + +from contextlib import asynccontextmanager + +from fastapi import FastAPI +from loguru import logger + +from kwai.api.app import create_api +from kwai.frontend.app import create_frontend + +APP_NAME = "kwai" + + +@asynccontextmanager +async def lifespan(app: FastAPI): + """Log the start/stop of the application.""" + logger.info(f"{APP_NAME} is starting") + yield + logger.warning(f"{APP_NAME} has ended!") + + +def create_app() -> FastAPI: + """Create the FastAPI application for API and frontend.""" + main_app = FastAPI(title=APP_NAME, lifespan=lifespan) + + api_app = create_api() + main_app.mount("/api", api_app) + + frontend_app = create_frontend() + main_app.mount("/", frontend_app) + + return main_app diff --git a/backend/src/kwai/core/args.py b/backend/src/kwai/core/args.py new file mode 100644 index 000000000..3d4038573 --- /dev/null +++ b/backend/src/kwai/core/args.py @@ -0,0 +1,21 @@ +"""Module for handling arguments for starting a uvicorn application.""" + +import argparse +from argparse import Namespace + + +def create_args(prog: str, default_port: int = 8000) -> Namespace: + """Parse and create cli arguments.""" + parser = argparse.ArgumentParser(prog=prog) + parser.add_argument( + "--reload", + action=argparse.BooleanOptionalAction, + help="Watch for code changes or not", + ) + parser.add_argument( + "--host", type=str, default="0.0.0.0", help="The host of the server." + ) + parser.add_argument( + "--port", type=int, default=default_port, help="The port of the server." + ) + return parser.parse_args() diff --git a/backend/src/kwai/core/db/database.py b/backend/src/kwai/core/db/database.py index a6c2d6c25..1330a9222 100644 --- a/backend/src/kwai/core/db/database.py +++ b/backend/src/kwai/core/db/database.py @@ -96,6 +96,8 @@ async def execute(self, query: AbstractQuery) -> int | None: async with self._connection.cursor() as cursor: try: await cursor.execute(compiled_query.sql, compiled_query.params) + if cursor.rowcount != -1: + self.log_affected_rows(cursor.rowcount) return cursor.lastrowid except Exception as exc: raise QueryException(compiled_query.sql) from exc @@ -243,6 +245,19 @@ def log_query(self, query: str): "DB: {database} - Query: {query}", database=self._settings.name, query=query ) + def log_affected_rows(self, rowcount: int): + """Log the number of affected rows of the last executed query. + + Args: + rowcount: The number of affected rows. + """ + db_logger = logger.bind(database=self._settings.name) + db_logger.info( + "DB: {database} - Affected rows: {rowcount}", + database=self._settings.name, + rowcount=rowcount, + ) + @property def settings(self) -> DatabaseSettings: """Return the database settings. diff --git a/backend/src/kwai/core/db/rows.py b/backend/src/kwai/core/db/rows.py index 9a0d065d6..d1da39304 100644 --- a/backend/src/kwai/core/db/rows.py +++ b/backend/src/kwai/core/db/rows.py @@ -4,6 +4,7 @@ from datetime import datetime from kwai.core.db.table import Table +from kwai.core.db.table_row import TableRow from kwai.core.domain.value_objects.identifier import IntIdentifier from kwai.core.domain.value_objects.name import Name from kwai.core.domain.value_objects.owner import Owner @@ -34,6 +35,26 @@ def create_owner(self) -> Owner: OwnersTable = Table("users", OwnerRow) +@dataclass(kw_only=True, frozen=True, slots=True) +class OwnerTableRow(TableRow): + """Represent the owner data.""" + + __table_name__ = "users" + + id: int + uuid: str + first_name: str + last_name: str + + def create_owner(self) -> Owner: + """Create an Author value object from row data.""" + return Owner( + id=IntIdentifier(self.id), + uuid=UniqueId.create_from_string(self.uuid), + name=Name(first_name=self.first_name, last_name=self.last_name), + ) + + @dataclass(kw_only=True, frozen=True, slots=True) class TextRow: """Represent a row for a content table. @@ -72,7 +93,7 @@ def create_text(self, author: Owner) -> LocaleText: summary=self.summary, author=author, traceable_time=TraceableTime( - created_at=Timestamp(timestamp=self.created_at), - updated_at=Timestamp(timestamp=self.updated_at), + created_at=Timestamp.create_utc(self.created_at), + updated_at=Timestamp.create_utc(self.updated_at), ), ) diff --git a/backend/src/kwai/core/db/table.py b/backend/src/kwai/core/db/table.py index 144cfd70a..d3bff8c90 100644 --- a/backend/src/kwai/core/db/table.py +++ b/backend/src/kwai/core/db/table.py @@ -1,15 +1,13 @@ """Module for the table decorator.""" from dataclasses import fields, is_dataclass -from typing import Any, Callable, Generic, TypeVar +from typing import Any, Callable from sql_smith.functions import alias from sql_smith.functions import field as sql_field -T = TypeVar("T", bound=Callable) - -class Table(Generic[T]): +class Table[T: Callable]: """Represent a table in the database. With this class a table row can be transformed into a dataclass. It can also @@ -30,7 +28,7 @@ def __call__(self, row: dict[str, Any], table_name: str | None = None) -> T: """Shortcut for map_row.""" return self.map_row(row, table_name) - def alias_name(self, column_name: str, table_name: str | None = None): + def alias_name(self, column_name: str, table_name: str | None = None) -> str: """Return an alias for a column. The alias will be the name of the table delimited with an diff --git a/backend/src/kwai/core/domain/entity.py b/backend/src/kwai/core/domain/entity.py index ef967693a..bdac872c0 100644 --- a/backend/src/kwai/core/domain/entity.py +++ b/backend/src/kwai/core/domain/entity.py @@ -1,6 +1,7 @@ """Module that defines a generic entity.""" + import inspect -from typing import Any, Generic, TypeVar +from typing import Any, Generic, Self, TypeVar from kwai.core.domain.value_objects.identifier import Identifier @@ -27,11 +28,11 @@ def has_id(self) -> bool: return not self._id.is_empty() @classmethod - def replace(cls, entity: "Entity[T]", **changes) -> Any: + def replace(cls, entity: Self, **changes: Any) -> Any: """Return a new entity from the existing entity. Args: - entity(Entity[T]): The entity to copy the values from + entity: The entity to copy the values from changes: the values to override when creating the new entity. Use the same keyword arguments as used on the class constructor (__init__) to diff --git a/backend/src/kwai/core/domain/presenter.py b/backend/src/kwai/core/domain/presenter.py new file mode 100644 index 000000000..5b15eb512 --- /dev/null +++ b/backend/src/kwai/core/domain/presenter.py @@ -0,0 +1,51 @@ +"""Module for defining a presenter.""" + +from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import AsyncIterator + + +@dataclass(frozen=True, kw_only=True, slots=True) +class IterableResult[T]: + """A dataclass used to represent a result with multiple entities.""" + + count: int + offset: int = 0 + limit: int = 0 + iterator: AsyncIterator[T] + + +class Presenter[T](ABC): + """An interface for a presenter. + + A presenter is used to transform an entity into another object that can be used + in a view. + + An example: convert to a JSON:API resource for returning the entity in a restful + API. + """ + + @abstractmethod + def present(self, use_case_result: T) -> None: + """Present the entity. + + This method is responsible for converting the entity. + """ + + +class AsyncPresenter[T](ABC): + """An interface for an async presenter. + + A presenter is used to transform an entity into another object that can be used + in a view. + + An example: convert to a JSON:API resource for returning the entity in a restful + API. + """ + + @abstractmethod + async def present(self, use_case_result: T) -> None: + """Present the entity. + + This method is responsible for converting the entity. + """ diff --git a/backend/src/kwai/core/domain/use_case.py b/backend/src/kwai/core/domain/use_case.py index 1ccbbd083..52d6e092d 100644 --- a/backend/src/kwai/core/domain/use_case.py +++ b/backend/src/kwai/core/domain/use_case.py @@ -1,7 +1,8 @@ """Module for defining common classes, functions, ... for use cases.""" + from abc import ABC, abstractmethod from dataclasses import dataclass -from typing import AsyncIterator, Generic, NamedTuple, TypeVar +from typing import AsyncIterator, NamedTuple class UseCaseResult(ABC): @@ -13,11 +14,8 @@ def to_message(self) -> str: raise NotImplementedError -T = TypeVar("T") - - @dataclass(kw_only=True, frozen=True, slots=True) -class NotFoundResult(UseCaseResult, Generic[T]): +class NotFoundResult[T](UseCaseResult): """A result that indicates that an entity was not found.""" entity_name: str @@ -28,7 +26,7 @@ def to_message(self) -> str: @dataclass(kw_only=True, frozen=True, slots=True) -class EntitiesResult(UseCaseResult, Generic[T]): +class EntitiesResult[T](UseCaseResult): """A result that returns an iterator for entities and the number of entities.""" count: int @@ -39,7 +37,7 @@ def to_message(self) -> str: @dataclass(kw_only=True, frozen=True, slots=True) -class EntityResult(UseCaseResult, Generic[T]): +class EntityResult[T](UseCaseResult): """A result that returns an entity.""" entity: T diff --git a/backend/src/kwai/core/domain/value_objects/identifier.py b/backend/src/kwai/core/domain/value_objects/identifier.py index 0e1008a9c..02c1b092c 100644 --- a/backend/src/kwai/core/domain/value_objects/identifier.py +++ b/backend/src/kwai/core/domain/value_objects/identifier.py @@ -1,11 +1,9 @@ """Module that defines identifiers.""" -from abc import ABC, abstractmethod -from typing import Generic, TypeVar -T = TypeVar("T") +from abc import ABC, abstractmethod -class Identifier(ABC, Generic[T]): +class Identifier[T](ABC): """Abstract and generic class for an identifier.""" def __init__(self, id_: T): diff --git a/backend/src/kwai/core/domain/value_objects/text.py b/backend/src/kwai/core/domain/value_objects/text.py index 62febb725..2f776ad22 100644 --- a/backend/src/kwai/core/domain/value_objects/text.py +++ b/backend/src/kwai/core/domain/value_objects/text.py @@ -1,6 +1,8 @@ """Module that defines a value object for text content.""" + from dataclasses import dataclass, field from enum import Enum +from typing import Self from kwai.core.domain.value_objects.owner import Owner from kwai.core.domain.value_objects.traceable_time import TraceableTime @@ -79,7 +81,7 @@ def get_translation(self, locale: Locale) -> LocaleText: The content, when available. Raises: - KeyError when the locale is not available. + KeyError: when the locale is not available. """ if locale in self._content: return self._content[locale] @@ -121,7 +123,7 @@ def remove_translation(self, content: LocaleText) -> "Text": new_dict.pop(content.locale) return Text(new_dict) - def replace_translation(self, content: LocaleText): + def replace_translation(self, content: LocaleText) -> Self: """Replace a translation. Args: diff --git a/backend/src/kwai/core/domain/value_objects/timestamp.py b/backend/src/kwai/core/domain/value_objects/timestamp.py index 99d4ca06d..2bf978013 100644 --- a/backend/src/kwai/core/domain/value_objects/timestamp.py +++ b/backend/src/kwai/core/domain/value_objects/timestamp.py @@ -1,7 +1,7 @@ """Module that defines a value object for a local timestamp.""" from dataclasses import dataclass -from datetime import date, datetime, time, timedelta +from datetime import date, datetime, time, timedelta, timezone @dataclass(frozen=True) @@ -24,7 +24,7 @@ def is_past(self) -> bool: if self.timestamp is None: raise ValueError("Empty timestamp") - return self.timestamp < datetime.utcnow() + return self.timestamp < Timestamp.create_now().timestamp @property def year(self) -> int: @@ -112,7 +112,7 @@ def create_with_delta(cls, **kwargs): @classmethod def create_now(cls): """Create a timestamp with the current UTC time.""" - return Timestamp(timestamp=datetime.utcnow()) + return Timestamp(timestamp=datetime.now(timezone.utc)) @classmethod def create_from_string( @@ -129,4 +129,17 @@ def create_from_string( return Timestamp() if len(date_time) == 0: return Timestamp() - return Timestamp(datetime.strptime(date_time, date_format)) + return Timestamp( + datetime.strptime(date_time, date_format).replace(tzinfo=timezone.utc) + ) + + @classmethod + def create_utc(cls, timestamp: datetime | None): + """Create a timestamp from a datetime and make it UTC. + + When None is passed, an empty timestamp will be returned. + """ + if timestamp is None: + return Timestamp() + + return Timestamp(timestamp=timestamp.replace(tzinfo=timezone.utc)) diff --git a/backend/src/kwai/core/domain/value_objects/unique_id.py b/backend/src/kwai/core/domain/value_objects/unique_id.py index dd1f575b1..5e16bb613 100644 --- a/backend/src/kwai/core/domain/value_objects/unique_id.py +++ b/backend/src/kwai/core/domain/value_objects/unique_id.py @@ -1,4 +1,5 @@ """Module that defines a value object for a unique id.""" + import uuid from dataclasses import dataclass @@ -26,3 +27,7 @@ def __eq__(self, other): def __str__(self): """Return a string representation.""" return str(self.id) + + def __hash__(self): + """Return a hash value for the unique id.""" + return hash(self.id) diff --git a/backend/src/kwai/core/events/event.py b/backend/src/kwai/core/events/event.py index b5e8d246a..f26d77d29 100644 --- a/backend/src/kwai/core/events/event.py +++ b/backend/src/kwai/core/events/event.py @@ -1,9 +1,11 @@ """Module that defines the base class Event.""" + import dataclasses from dataclasses import dataclass -from datetime import datetime from typing import ClassVar +from kwai.core.domain.value_objects.timestamp import Timestamp + @dataclass(kw_only=True, frozen=True) class EventMeta: @@ -26,7 +28,7 @@ def data(self) -> dict: return { "meta": { **dataclasses.asdict(self.__class__.meta), - "date": datetime.utcnow().isoformat(sep=" ", timespec="milliseconds"), + "date": str(Timestamp.create_now()), }, "data": {**dataclasses.asdict(self)}, } diff --git a/backend/src/kwai/core/events/stream.py b/backend/src/kwai/core/events/stream.py index 2976432e9..1a9269b47 100644 --- a/backend/src/kwai/core/events/stream.py +++ b/backend/src/kwai/core/events/stream.py @@ -1,4 +1,5 @@ """Define a Redis stream.""" + import json from dataclasses import dataclass, field from json import JSONDecodeError @@ -131,7 +132,11 @@ async def add(self, message: RedisMessage) -> RedisMessage: return RedisMessage(id=message_id.decode("utf-8"), data=message.data) async def consume( - self, group_name: str, consumer_name: str, id_=">", block: int | None = None + self, + group_name: str, + consumer_name: str, + id_: str = ">", + block: int | None = None, ) -> RedisMessage | None: """Consume a message from a stream. @@ -156,7 +161,7 @@ async def consume( return RedisMessage.create_from_redis(messages) - async def create_group(self, group_name: str, id_="$") -> bool: + async def create_group(self, group_name: str, id_: str = "$") -> bool: """Create a group (if it doesn't exist yet). Args: diff --git a/backend/src/kwai/core/functions.py b/backend/src/kwai/core/functions.py index bad8a3712..70d9b256e 100644 --- a/backend/src/kwai/core/functions.py +++ b/backend/src/kwai/core/functions.py @@ -1,15 +1,12 @@ """Module that defines some common functions.""" from itertools import count -from typing import Any, AsyncIterator, Callable, Generator, TypeVar +from typing import Any, AsyncIterator, Callable, Generator -T = TypeVar("T") -R = TypeVar("R") - -async def async_groupby( - it: AsyncIterator[T], key: Callable[[T], R] -) -> AsyncIterator[tuple[Any, list[T]]]: +async def async_groupby[ + T, R +](it: AsyncIterator[T], key: Callable[[T], R]) -> AsyncIterator[tuple[Any, list[T]]]: """An async groupby.""" try: row = await anext(it) diff --git a/backend/src/kwai/core/json_api.py b/backend/src/kwai/core/json_api.py index a0971a0d4..e48e3fa99 100644 --- a/backend/src/kwai/core/json_api.py +++ b/backend/src/kwai/core/json_api.py @@ -1,6 +1,6 @@ """Module that defines some JSON:API related models.""" -from typing import Any, Generic, TypeVar, cast +from typing import Any, cast from fastapi import Query from pydantic import ( @@ -25,13 +25,10 @@ def __hash__(self) -> int: return hash(str(self.id) + self.type) -T_RELATION_SHIP = TypeVar("T_RELATION_SHIP") - - -class Relationship(BaseModel, Generic[T_RELATION_SHIP]): +class Relationship[R](BaseModel): """A JSON:API relationship.""" - data: T_RELATION_SHIP | list[T_RELATION_SHIP] | None + data: R | list[R] | None class ResourceMeta(BaseModel): @@ -43,16 +40,12 @@ class ResourceMeta(BaseModel): updated_at: str | None = None -T_ATTRS = TypeVar("T_ATTRS") -T_RELATIONSHIPS = TypeVar("T_RELATIONSHIPS") - - -class ResourceData(BaseModel, Generic[T_ATTRS, T_RELATIONSHIPS]): +class ResourceData[A, R](BaseModel): """A JSON:API resource.""" meta: ResourceMeta | SkipJsonSchema[None] = None - attributes: T_ATTRS - relationships: T_RELATIONSHIPS | SkipJsonSchema[None] = None + attributes: A + relationships: R | SkipJsonSchema[None] = None @model_serializer(mode="wrap") def serialize(self, handler) -> dict[str, Any]: @@ -65,10 +58,6 @@ def serialize(self, handler) -> dict[str, Any]: return result -T_RESOURCE = TypeVar("T_RESOURCE") -T_INCLUDE = TypeVar("T_INCLUDE") - - class Meta(BaseModel): """Defines the metadata for the document model. @@ -87,15 +76,31 @@ class Meta(BaseModel): limit: int | None = None -class Document(BaseModel, Generic[T_RESOURCE, T_INCLUDE]): +class ErrorSource(BaseModel): + """Defines the model for an error source.""" + + pointer: str + + +class Error(BaseModel): + """Defines the model for a JSON:API error.""" + + status: str = "" + source: ErrorSource | None = None + title: str = "" + detail: str = "" + + +class Document[R, I](BaseModel): """A JSON:API document.""" meta: Meta | SkipJsonSchema[None] = None - data: T_RESOURCE | list[T_RESOURCE] - included: set[T_INCLUDE] | SkipJsonSchema[None] = None + data: R | list[R] + included: set[I] | SkipJsonSchema[None] = None + errors: list[Error] | SkipJsonSchema[None] = None @property - def resource(self) -> T_RESOURCE: + def resource(self) -> R: """Return the resource of this document. An assert will occur, when the resource is a list. @@ -104,7 +109,7 @@ def resource(self) -> T_RESOURCE: return self.data @property - def resources(self) -> list[T_RESOURCE]: + def resources(self) -> list[R]: """Return the list of resources of this document. An assert will occur, when the resource is not a list. @@ -112,6 +117,16 @@ def resources(self) -> list[T_RESOURCE]: assert isinstance(self.data, list) return self.data + def __repr__(self): + """Return representation of a document.""" + if isinstance(self.data, list): + if len(self.data) > 0: + return f"<{self.__class__.__name__} type={self.data[0].type}[]>" + else: + return f"<{self.__class__.__name__} type=[]>" + else: + return f"<{self.__class__.__name__} type={self.data.type}>" + @classmethod def __get_pydantic_json_schema__( cls, @@ -135,6 +150,8 @@ def serialize(self, handler) -> dict[str, Any]: del result["included"] if self.meta is None: del result["meta"] + if not self.errors: + del result["errors"] return result def merge(self, other: "Document"): @@ -167,3 +184,14 @@ class PaginationModel(BaseModel): offset: int | None = Field(Query(default=None, alias="page[offset]")) limit: int | None = Field(Query(default=None, alias="page[limit]")) + + +class JsonApiPresenter[Document]: + """An interface for a presenter that generates a JSON:API document.""" + + def __init__(self): + self._document: Document = None + + def get_document(self) -> Document: + """Return the JSON:API document.""" + return self._document diff --git a/backend/src/kwai/core/settings.py b/backend/src/kwai/core/settings.py index 4b09d6bce..e8e2df76f 100644 --- a/backend/src/kwai/core/settings.py +++ b/backend/src/kwai/core/settings.py @@ -1,4 +1,5 @@ """Module for the settings of this application.""" + import os from functools import lru_cache @@ -12,6 +13,33 @@ class SettingsException(Exception): """Raised when a problem occurred while loading the settings.""" +class FrontendApplicationSettings(BaseModel): + """Settings for a frontend application.""" + + server: str | None = None + base: str | None = None + entries: list[str] | str + + +class FrontendApplications(BaseModel): + """All applications.""" + + auth: FrontendApplicationSettings + author: FrontendApplicationSettings + club: FrontendApplicationSettings + coach: FrontendApplicationSettings + portal: FrontendApplicationSettings + + +class FrontendSettings(BaseModel): + """Settings for the frontend.""" + + test: bool = False + path: str + apps: FrontendApplications + root_app: str + + class FilesSettings(BaseModel): """Settings for files (upload).""" @@ -92,6 +120,8 @@ class TemplateSettings(BaseModel): class Settings(BaseModel): """Class with settings.""" + frontend: FrontendSettings + files: FilesSettings security: SecuritySettings diff --git a/backend/src/kwai/frontend/__init__.py b/backend/src/kwai/frontend/__init__.py new file mode 100644 index 000000000..c656fddb5 --- /dev/null +++ b/backend/src/kwai/frontend/__init__.py @@ -0,0 +1 @@ +"""Package that defines modules for serving the frontend from the Python backend.""" diff --git a/backend/src/kwai/frontend/app.py b/backend/src/kwai/frontend/app.py new file mode 100644 index 000000000..484b2c14f --- /dev/null +++ b/backend/src/kwai/frontend/app.py @@ -0,0 +1,73 @@ +"""Module that defines a sub application for handling the frontend.""" + +import uuid +from pathlib import Path +from typing import Annotated + +from fastapi import Depends, FastAPI, Request, status +from fastapi.responses import JSONResponse, RedirectResponse +from loguru import logger + +from kwai.core.settings import Settings, get_settings +from kwai.frontend.apps import application_routers + + +def create_frontend(): + """Create the frontend.""" + frontend_app = FastAPI() + + @frontend_app.middleware("http") + async def log(request: Request, call_next): + """Middleware for logging the requests.""" + request_id = str(uuid.uuid4()) + with logger.contextualize(request_id=request_id): + logger.info(f"{request.url} - {request.method} - Request started") + + response = None # Make pylint happy... + try: + response = await call_next(request) + except Exception as ex: + logger.error(f"{request.url} - Request failed: {ex}") + logger.exception(ex) + response = JSONResponse( + content={ + "detail": str(ex), + }, + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + ) + finally: + response.headers["X-Request-ID"] = request_id + logger.info( + f"{request.url} - {request.method} - Request ended: " + f"{response.status_code}" + ) + + return response + + for router in application_routers: + frontend_app.include_router(router, prefix="/apps") + + @frontend_app.get("/news/{path:path}", name="frontend.news") + def news(path: Path, settings: Annotated[Settings, Depends(get_settings)]): + """Redirect the news path to the portal application. + + When FastAPI serves the frontend, the root path can't be used for the portal. + So redirect this url to the root application. + """ + return RedirectResponse(f"/apps/{settings.frontend.root_app}/news/{path}") + + @frontend_app.get("/pages/{path:path}", name="frontend.pages") + def pages(path: Path, settings: Annotated[Settings, Depends(get_settings)]): + """Redirect the pages path to the portal application. + + When FastAPI serves the frontend, the root path can't be used for the portal. + So redirect this url to the root application. + """ + return RedirectResponse(f"/apps/{settings.frontend.root_app}/pages/{path}") + + @frontend_app.get("/", name="frontend.home") + def root(settings: Annotated[Settings, Depends(get_settings)]): + """Redirect index to the portal application.""" + return RedirectResponse(f"/apps/{settings.frontend.root_app}") + + return frontend_app diff --git a/backend/src/kwai/frontend/apps/__init__.py b/backend/src/kwai/frontend/apps/__init__.py new file mode 100644 index 000000000..8a700ff75 --- /dev/null +++ b/backend/src/kwai/frontend/apps/__init__.py @@ -0,0 +1,15 @@ +"""Package for defining the routes for all frontend applications.""" + +from kwai.frontend.apps._auth import router as auth_router +from kwai.frontend.apps._author import router as author_router +from kwai.frontend.apps._club import router as club_router +from kwai.frontend.apps._coach import router as coach_router +from kwai.frontend.apps._portal import router as portal_router + +application_routers = [ + auth_router, + author_router, + club_router, + coach_router, + portal_router, +] diff --git a/backend/src/kwai/frontend/apps/_auth.py b/backend/src/kwai/frontend/apps/_auth.py new file mode 100644 index 000000000..89e982b03 --- /dev/null +++ b/backend/src/kwai/frontend/apps/_auth.py @@ -0,0 +1,46 @@ +"""Module that defines the routes for the authentication frontend application.""" + +from pathlib import Path +from typing import Annotated + +from fastapi import APIRouter, Depends, Request +from fastapi.templating import Jinja2Templates + +from kwai.api.dependencies import create_templates +from kwai.frontend.dependencies import ViteDependency +from kwai.frontend.etag_file_response import EtagFileResponse +from kwai.frontend.vite import Vite + +APP_NAME = "auth" + +router = APIRouter(prefix=f"/{APP_NAME}") + +_auth_vite_dependency = ViteDependency(APP_NAME) + + +@router.get("/{path:path}", name=APP_NAME) +async def get_app( + path: Path, + request: Request, + templates: Annotated[Jinja2Templates, Depends(create_templates)], + vite: Annotated[Vite, Depends(_auth_vite_dependency)], +): + asset_file_path = vite.get_asset_path(path) + if asset_file_path is not None: + return EtagFileResponse(asset_file_path) + + url = request.url_for(APP_NAME, path="") + if "x-forwarded-proto" in request.headers: + url = url.replace(scheme=request.headers["x-forwarded-proto"]) + + return templates.TemplateResponse( + "index.jinja2", + { + "application": { + "name": APP_NAME, + "url": str(url), + }, + "request": request, + "vite": vite, + }, + ) diff --git a/backend/src/kwai/frontend/apps/_author.py b/backend/src/kwai/frontend/apps/_author.py new file mode 100644 index 000000000..71faf6208 --- /dev/null +++ b/backend/src/kwai/frontend/apps/_author.py @@ -0,0 +1,46 @@ +"""Module that defines the routes for the author frontend application.""" + +from pathlib import Path +from typing import Annotated + +from fastapi import APIRouter, Depends, Request +from fastapi.templating import Jinja2Templates + +from kwai.api.dependencies import create_templates +from kwai.frontend.dependencies import ViteDependency +from kwai.frontend.etag_file_response import EtagFileResponse +from kwai.frontend.vite import Vite + +APP_NAME = "author" + +router = APIRouter(prefix=f"/{APP_NAME}") + +_auth_vite_dependency = ViteDependency(APP_NAME) + + +@router.get("/{path:path}", name=APP_NAME) +async def get_app( + path: Path, + request: Request, + templates: Annotated[Jinja2Templates, Depends(create_templates)], + vite: Annotated[Vite, Depends(_auth_vite_dependency)], +): + asset_file_path = vite.get_asset_path(path) + if asset_file_path is not None: + return EtagFileResponse(asset_file_path) + + url = request.url_for(APP_NAME, path="") + if "x-forwarded-proto" in request.headers: + url = url.replace(scheme=request.headers["x-forwarded-proto"]) + + return templates.TemplateResponse( + "index.jinja2", + { + "application": { + "name": APP_NAME, + "url": str(url), + }, + "request": request, + "vite": vite, + }, + ) diff --git a/backend/src/kwai/frontend/apps/_club.py b/backend/src/kwai/frontend/apps/_club.py new file mode 100644 index 000000000..fa490c7ca --- /dev/null +++ b/backend/src/kwai/frontend/apps/_club.py @@ -0,0 +1,46 @@ +"""Module that defines the routes for the club frontend application.""" + +from pathlib import Path +from typing import Annotated + +from fastapi import APIRouter, Depends, Request +from fastapi.templating import Jinja2Templates + +from kwai.api.dependencies import create_templates +from kwai.frontend.dependencies import ViteDependency +from kwai.frontend.etag_file_response import EtagFileResponse +from kwai.frontend.vite import Vite + +APP_NAME = "club" + +router = APIRouter(prefix=f"/{APP_NAME}") + +_club_vite_dependency = ViteDependency(APP_NAME) + + +@router.get("/{path:path}", name=APP_NAME) +async def get_app( + path: Path, + request: Request, + templates: Annotated[Jinja2Templates, Depends(create_templates)], + vite: Annotated[Vite, Depends(_club_vite_dependency)], +): + asset_file_path = vite.get_asset_path(path) + if asset_file_path is not None: + return EtagFileResponse(asset_file_path) + + url = request.url_for(APP_NAME, path="") + if "x-forwarded-proto" in request.headers: + url = url.replace(scheme=request.headers["x-forwarded-proto"]) + + return templates.TemplateResponse( + "index.jinja2", + { + "application": { + "name": APP_NAME, + "url": str(url), + }, + "request": request, + "vite": vite, + }, + ) diff --git a/backend/src/kwai/frontend/apps/_coach.py b/backend/src/kwai/frontend/apps/_coach.py new file mode 100644 index 000000000..d2e3c5d0e --- /dev/null +++ b/backend/src/kwai/frontend/apps/_coach.py @@ -0,0 +1,46 @@ +"""Module that defines the routes for the coach frontend application.""" + +from pathlib import Path +from typing import Annotated + +from fastapi import APIRouter, Depends, Request +from fastapi.templating import Jinja2Templates + +from kwai.api.dependencies import create_templates +from kwai.frontend.dependencies import ViteDependency +from kwai.frontend.etag_file_response import EtagFileResponse +from kwai.frontend.vite import Vite + +APP_NAME = "coach" + +router = APIRouter(prefix=f"/{APP_NAME}") + +_coach_vite_dependency = ViteDependency(APP_NAME) + + +@router.get("/{path:path}", name=APP_NAME) +async def get_app( + path: Path, + request: Request, + templates: Annotated[Jinja2Templates, Depends(create_templates)], + vite: Annotated[Vite, Depends(_coach_vite_dependency)], +): + asset_file_path = vite.get_asset_path(path) + if asset_file_path is not None: + return EtagFileResponse(asset_file_path) + + url = request.url_for(APP_NAME, path="") + if "x-forwarded-proto" in request.headers: + url = url.replace(scheme=request.headers["x-forwarded-proto"]) + + return templates.TemplateResponse( + "index.jinja2", + { + "application": { + "name": APP_NAME, + "url": str(url), + }, + "request": request, + "vite": vite, + }, + ) diff --git a/backend/src/kwai/frontend/apps/_portal.py b/backend/src/kwai/frontend/apps/_portal.py new file mode 100644 index 000000000..a544eee24 --- /dev/null +++ b/backend/src/kwai/frontend/apps/_portal.py @@ -0,0 +1,46 @@ +"""Module that defines the routes for the portal frontend application.""" + +from pathlib import Path +from typing import Annotated + +from fastapi import APIRouter, Depends, Request +from fastapi.templating import Jinja2Templates + +from kwai.api.dependencies import create_templates +from kwai.frontend.dependencies import ViteDependency +from kwai.frontend.etag_file_response import EtagFileResponse +from kwai.frontend.vite import Vite + +APP_NAME = "portal" + +router = APIRouter(prefix=f"/{APP_NAME}") + +_portal_vite_dependency = ViteDependency(APP_NAME) + + +@router.get("/{path:path}", name=APP_NAME) +async def get_app( + path: Path, + request: Request, + templates: Annotated[Jinja2Templates, Depends(create_templates)], + vite: Annotated[Vite, Depends(_portal_vite_dependency)], +): + asset_file_path = vite.get_asset_path(path) + if asset_file_path is not None: + return EtagFileResponse(asset_file_path) + + url = request.url_for(APP_NAME, path="") + if "x-forwarded-proto" in request.headers: + url = url.replace(scheme=request.headers["x-forwarded-proto"]) + + return templates.TemplateResponse( + "index.jinja2", + { + "application": { + "name": APP_NAME, + "url": str(url), + }, + "request": request, + "vite": vite, + }, + ) diff --git a/backend/src/kwai/frontend/dependencies.py b/backend/src/kwai/frontend/dependencies.py new file mode 100644 index 000000000..94a5a61a8 --- /dev/null +++ b/backend/src/kwai/frontend/dependencies.py @@ -0,0 +1,57 @@ +"""Module for defining dependencies for the frontend applications.""" + +from pathlib import Path +from typing import Annotated + +from fastapi import Depends, HTTPException, status + +from kwai.core.settings import Settings, get_settings +from kwai.frontend.vite import DevelopmentVite, ProductionVite, Vite + + +class ViteDependency: + """Vite is a dependency.""" + + def __init__(self, application_name: str): + self._application_name = application_name + + def __call__(self, settings: Annotated[Settings, Depends(get_settings)]) -> Vite: + """Create a Vite environment for this application.""" + if not hasattr(settings.frontend.apps, self._application_name): + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Application {self._application_name} does not exist.", + ) + + app_setting = getattr(settings.frontend.apps, self._application_name) + if settings.frontend.test: + if app_setting.server is None: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Setting 'server' not set for application {self._application_name}", + ) + if app_setting.base is None: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Setting 'base' not set for application {self._application_name}", + ) + return DevelopmentVite(app_setting.server, app_setting.base) + + manifest_path = ( + Path(settings.frontend.path) + / "apps" + / self._application_name + / "dist" + / ".vite" + / "manifest.json" + ) + if not manifest_path.exists(): + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail=f"Manifest file {manifest_path} not found", + ) + + return ProductionVite( + manifest_path, + Path(settings.frontend.path) / "apps" / self._application_name, + ) diff --git a/backend/src/kwai/frontend/etag_file_response.py b/backend/src/kwai/frontend/etag_file_response.py new file mode 100644 index 000000000..daf9a9992 --- /dev/null +++ b/backend/src/kwai/frontend/etag_file_response.py @@ -0,0 +1,39 @@ +from starlette._compat import md5_hexdigest # noqa +from pathlib import Path + +from fastapi import Request +from fastapi.responses import FileResponse, Response + + +class EtagFileResponse(FileResponse): + """A FileResponse that will check the etag when if-none-match header is passed. + + _generate_etag uses the same implementation as FileResponse. + FileResponse automatically sets the etag header with this etag value. + """ + + def __init__(self, path: Path, **kwargs) -> None: + super().__init__(path, **kwargs) + self._path = path + + def _generate_etag(self) -> str: + file_stat = self._path.stat() + etag_base = str(file_stat.st_mtime) + "-" + str(file_stat.st_size) + return f'"{md5_hexdigest(etag_base.encode(), usedforsecurity=False)}"' + + async def __call__(self, scope, receive, send) -> None: + """Check the etag, and return 304 when the file is not modified.""" + request = Request(scope, receive) + if_none_match = request.headers.get("if-none-match") + + if not if_none_match: + await super().__call__(scope, receive, send) + return + + etag = self._generate_etag() + if if_none_match == etag: + response = Response(status_code=304) + await response(scope, receive, send) + return + + await super().__call__(scope, receive, send) diff --git a/backend/src/kwai/frontend/manifest.py b/backend/src/kwai/frontend/manifest.py new file mode 100644 index 000000000..5ef5606dd --- /dev/null +++ b/backend/src/kwai/frontend/manifest.py @@ -0,0 +1,71 @@ +"""Module that defines a class for handling the manifest file of Vite.""" + +import json +from dataclasses import dataclass, field +from pathlib import Path +from typing import Self + + +@dataclass(frozen=True, kw_only=True, slots=True) +class Chunk: + """An entry of a manifest file.""" + + src: str | None = None + name: str | None = None + entry: bool = False + dynamic_entry: bool = False + file: str + css: list[str] = field(default_factory=list) + assets: list[str] = field(default_factory=list) + imports: list[str] = field(default_factory=list) + dynamic_imports: list[str] = field(default_factory=list) + + +class Manifest: + """Class for handling a manifest file of Vite.""" + + def __init__(self, entries: dict[str, Chunk]) -> None: + """Initialize the Manifest class.""" + self._entries = entries + + @property + def chunks(self): + """Return the entries.""" + return self._entries.copy() + + def has_chunk(self, entry_name: str): + """Check if the entry exists in the manifest file.""" + return entry_name in self._entries + + def get_chunk(self, entry_name: str) -> Chunk: + """Return the entry with the given name.""" + return self._entries[entry_name] + + @classmethod + def load_from_file(cls, file_path: Path) -> Self: + """Load the manifest from a file.""" + with open(file_path, "r") as manifest_file: + return cls.load_from_string(manifest_file.read()) + + @classmethod + def load_from_string(cls, content: str) -> Self: + """Load the manifest from a string.""" + entries: dict[str, Chunk] = {} + json_data = json.loads(content) + for k, v in json_data.items(): + if not isinstance(v, dict): + continue + entry = Chunk( + src=v.get("src", None), + name=v.get("name", None), + entry=v.get("isEntry", False), + dynamic_entry=v.get("isDynamicEntry", False), + file=v.get("file"), + css=v.get("css", []), + assets=v.get("assets", []), + imports=v.get("imports", []), + dynamic_imports=v.get("dynamicImports", []), + ) + entries[k] = entry + + return cls(entries=entries) diff --git a/backend/src/kwai/frontend/vite.py b/backend/src/kwai/frontend/vite.py new file mode 100644 index 000000000..72cd6f614 --- /dev/null +++ b/backend/src/kwai/frontend/vite.py @@ -0,0 +1,171 @@ +"""Module for defining a class that handles files and assets created with vite.""" + +from abc import ABC, abstractmethod +from pathlib import Path + +from kwai.frontend.manifest import Chunk, Manifest + + +class Vite(ABC): + """Interface for a Vite runtime.""" + + @abstractmethod + def init(self, *entries: str): + """Initialize the Vite runtime for the given entries.""" + raise NotImplementedError + + @abstractmethod + def get_scripts(self, base_url: str) -> list[str]: + """Get the scripts for the given entries.""" + raise NotImplementedError + + @abstractmethod + def get_css(self, base_url: str) -> list[str]: + """Get the css files for the given entries.""" + raise NotImplementedError + + @abstractmethod + def get_preloads(self, base_url: str) -> list[str]: + """Get the preloads for the given entries.""" + raise NotImplementedError + + @abstractmethod + def get_asset_path(self, asset_path: Path) -> Path | None: + """Return the path for an asset. + + None is returned when the file should not be processed. This is the case + in the development environment, because Vite will serve the assets. + + None should also be returned when the file does not exist in the dist folder. + This way, the url path will be handled by Vue Router. + + When the path starts with public, the path without 'public' is used to search + the file in the dist folder. + """ + + +class DevelopmentVite(Vite): + """Vite implementation for development.""" + + def __init__(self, server_url: str, base_path: str): + """Initialize the development version of vite. + + Args: + server_url: The url for the vite server + base_path: The base path for the development version of vite. + + !!! Note + When vite is configured with a base then make sure that this + base is also part of the base_path argument. For example: when base is + '/apps/author' and the server is running on localhost with port 3001, then + base_path should be: 'http://localhost:3001/apps/author'. + """ + self._server_url = server_url + self._base_path = base_path + self._entries: list[str] = [] + + def init(self, *entries: str): + self._entries = entries + + def get_scripts(self, base_url: str) -> list[str]: + scripts = [f"{self._server_url}/@vite/client"] + for entry in self._entries: + scripts.append( + "/".join( + list( + filter( + lambda item: item, + [self._server_url, self._base_path, entry], + ) + ) + ) + ) + return scripts + + def get_css(self, base_url: str) -> list[str]: + return [] + + def get_preloads(self, base_url: str) -> list[str]: + return [] + + def get_asset_path(self, asset_path: Path) -> Path | None: + return None + + +class ProductionVite(Vite): + """Vite implementation for production.""" + + def __init__(self, manifest_filepath: Path, base_path: Path): + """Initialize the production Vite runtime. + + Args: + manifest_filepath: Path to the manifest file. + base_path: Path to the dist folder. + """ + self._manifest_filepath: Path = manifest_filepath + self._base_path: Path = base_path + self._manifest: Manifest | None = None + self._imported_chunks: dict[str, Chunk] = {} # chunks imported by the entries + + def init(self, *entries: str): + """Load the manifest file.""" + self._manifest = Manifest.load_from_file(self._manifest_filepath) + self._imported_chunks = self._find_imported_chunks(*entries) + + def get_scripts(self, base_url: str) -> list[str]: + scripts = [] + + for chunk in self._imported_chunks.values(): + if chunk.entry: + scripts.append(base_url + chunk.file) + + return scripts + + def get_css(self, base_url: str) -> list[str]: + styles = [] + for chunk in self._imported_chunks.values(): + for css in chunk.css: + styles.append(base_url + css) + return styles + + def get_preloads(self, base_url: str) -> list[str]: + preloads = [] + + for chunk in self._imported_chunks.values(): + if chunk.file.endswith(".js") and not chunk.entry: + preloads.append(base_url + chunk.file) + + return preloads + + def _find_imported_chunks(self, *entries: str) -> dict[str, Chunk]: + chunks = {} + + for entry in entries: + if not self._manifest.has_chunk(entry): + raise ValueError(f"{entry} is not a chunk in {self._manifest_filepath}") + + chunk = self._manifest.get_chunk(entry) + if not chunk.entry: + raise ValueError( + f"{entry} is not an entry point in {self._manifest_filepath}" + ) + + chunks[entry] = chunk + + imports = chunk.imports + while imports: + import_ = imports.pop() + if import_ not in chunks: + import_chunk = self._manifest.get_chunk(import_) + chunks[import_] = import_chunk + imports.extend(import_chunk.imports) + + return chunks + + def get_asset_path(self, path: Path) -> Path | None: + dist_path = self._base_path / "dist" + asset_file = dist_path / path + if asset_file.is_relative_to(dist_path) and asset_file.is_file(): + return asset_file + + return None diff --git a/backend/src/kwai/modules/club/domain/__init__.py b/backend/src/kwai/modules/club/domain/__init__.py new file mode 100644 index 000000000..42179d38e --- /dev/null +++ b/backend/src/kwai/modules/club/domain/__init__.py @@ -0,0 +1 @@ +"""Package for entities and value objects.""" diff --git a/backend/src/kwai/modules/club/domain/coach.py b/backend/src/kwai/modules/club/domain/coach.py new file mode 100644 index 000000000..8f18fa80d --- /dev/null +++ b/backend/src/kwai/modules/club/domain/coach.py @@ -0,0 +1,92 @@ +"""Module for defining a coach entity.""" + +from kwai.core.domain.entity import Entity +from kwai.core.domain.value_objects.identifier import IntIdentifier +from kwai.core.domain.value_objects.name import Name +from kwai.core.domain.value_objects.owner import Owner +from kwai.core.domain.value_objects.traceable_time import TraceableTime +from kwai.modules.club.domain.member import MemberEntity + +CoachIdentifier = IntIdentifier + + +class CoachEntity(Entity[CoachIdentifier]): + """A coach entity.""" + + def __init__( + self, + *, + id_: CoachIdentifier | None = None, + member: MemberEntity, + description: str = "", + diploma: str = "", + active: bool = True, + remark: str = "", + user: Owner | None = None, + traceable_time: TraceableTime | None = None, + ): + """Initialize a coach. + + Args: + id_ (CoachIdentifier): The id of the coach. + member: A coach is a member of the club. + description: The description (bio) of the coach. + diploma: The diploma of the coach. + active: Whether the coach is active. + remark: A remark about the coach. + user: A coach can also be a user of the system. + traceable_time: The creation and modification timestamp of the coach. + """ + super().__init__(id_ or CoachIdentifier()) + self._member = member + self._description = description + self._diploma = diploma + self._active = active + self._remark = remark + self._user = user + self._traceable_time = traceable_time or TraceableTime() + + @property + def is_active(self) -> bool: + """Is the coach active?""" + return self._active + + @property + def member(self) -> MemberEntity: + """Return the related member.""" + return self._member + + @property + def name(self) -> Name: + """Return the name of the coach.""" + return self._member.person.name + + @property + def diploma(self) -> str: + """Return the diploma of the coach.""" + return self._diploma + + @property + def description(self) -> str: + """Return the description of the coach.""" + return self._description + + @property + def remark(self) -> str: + """Return the remark of the coach.""" + return self._remark + + @property + def traceable_time(self) -> TraceableTime: + """Return the traceable_time.""" + return self._traceable_time + + @property + def uuid(self): + """Return the uuid of the coach.""" + return self._member.uuid + + @property + def user(self) -> Owner | None: + """Return the related user.""" + return self._user diff --git a/backend/src/kwai/modules/club/members/contact.py b/backend/src/kwai/modules/club/domain/contact.py similarity index 97% rename from backend/src/kwai/modules/club/members/contact.py rename to backend/src/kwai/modules/club/domain/contact.py index ba7ef04f3..3634c9a40 100644 --- a/backend/src/kwai/modules/club/members/contact.py +++ b/backend/src/kwai/modules/club/domain/contact.py @@ -4,7 +4,7 @@ from kwai.core.domain.value_objects.email_address import EmailAddress from kwai.core.domain.value_objects.identifier import IntIdentifier from kwai.core.domain.value_objects.traceable_time import TraceableTime -from kwai.modules.club.members.value_objects import Address +from kwai.modules.club.domain.value_objects import Address ContactIdentifier = IntIdentifier diff --git a/backend/src/kwai/modules/club/members/country.py b/backend/src/kwai/modules/club/domain/country.py similarity index 100% rename from backend/src/kwai/modules/club/members/country.py rename to backend/src/kwai/modules/club/domain/country.py diff --git a/backend/src/kwai/modules/club/members/file_upload.py b/backend/src/kwai/modules/club/domain/file_upload.py similarity index 89% rename from backend/src/kwai/modules/club/members/file_upload.py rename to backend/src/kwai/modules/club/domain/file_upload.py index 59911bc4a..f0974740a 100644 --- a/backend/src/kwai/modules/club/members/file_upload.py +++ b/backend/src/kwai/modules/club/domain/file_upload.py @@ -20,6 +20,7 @@ def __init__( filename: str, owner: Owner, remark: str = "", + preview: bool = False, traceable_time: TraceableTime | None = None, ): """Initialize a file upload entity. @@ -28,8 +29,9 @@ def __init__( id_: The id of the upload. uuid: The unique id of the upload. filename: The name of the file. - remark: A remark about the upload. owner: The user who uploaded the file. + remark: A remark about the upload. + preview: Whether the upload is a preview. traceable_time: The creation and modification timestamp of the upload. """ super().__init__(id_ or FileUploadIdentifier()) @@ -37,6 +39,7 @@ def __init__( self._filename = filename self._owner = owner self._remark = remark + self._preview = preview self._traceable_time = traceable_time or TraceableTime() @property @@ -59,6 +62,11 @@ def uuid(self) -> UniqueId: """Return the uuid.""" return self._uuid + @property + def preview(self) -> bool: + """Return the preview.""" + return self._preview + @property def traceable_time(self) -> TraceableTime: """Return the creation/modification time.""" diff --git a/backend/src/kwai/modules/club/members/member.py b/backend/src/kwai/modules/club/domain/member.py similarity index 89% rename from backend/src/kwai/modules/club/members/member.py rename to backend/src/kwai/modules/club/domain/member.py index 657ad03c1..7b271d5b4 100644 --- a/backend/src/kwai/modules/club/members/member.py +++ b/backend/src/kwai/modules/club/domain/member.py @@ -1,10 +1,12 @@ """Module for defining the Member entity.""" + from kwai.core.domain.entity import Entity from kwai.core.domain.value_objects.identifier import IntIdentifier +from kwai.core.domain.value_objects.name import Name from kwai.core.domain.value_objects.traceable_time import TraceableTime from kwai.core.domain.value_objects.unique_id import UniqueId -from kwai.modules.club.members.person import PersonEntity -from kwai.modules.club.members.value_objects import License +from kwai.modules.club.domain.person import PersonEntity +from kwai.modules.club.domain.value_objects import License MemberIdentifier = IntIdentifier @@ -60,6 +62,11 @@ def license(self) -> License: """Return the license.""" return self._license + @property + def name(self) -> Name: + """Return the name of the member.""" + return self.person.name + @property def person(self) -> PersonEntity: """Return the person.""" diff --git a/backend/src/kwai/modules/club/members/person.py b/backend/src/kwai/modules/club/domain/person.py similarity index 92% rename from backend/src/kwai/modules/club/members/person.py rename to backend/src/kwai/modules/club/domain/person.py index c43815025..1ab08dd14 100644 --- a/backend/src/kwai/modules/club/members/person.py +++ b/backend/src/kwai/modules/club/domain/person.py @@ -4,9 +4,9 @@ from kwai.core.domain.value_objects.identifier import IntIdentifier from kwai.core.domain.value_objects.name import Name from kwai.core.domain.value_objects.traceable_time import TraceableTime -from kwai.modules.club.members.contact import ContactEntity -from kwai.modules.club.members.country import CountryEntity -from kwai.modules.club.members.value_objects import Birthdate, Gender +from kwai.modules.club.domain.contact import ContactEntity +from kwai.modules.club.domain.country import CountryEntity +from kwai.modules.club.domain.value_objects import Birthdate, Gender PersonIdentifier = IntIdentifier diff --git a/backend/src/kwai/modules/club/members/value_objects.py b/backend/src/kwai/modules/club/domain/value_objects.py similarity index 95% rename from backend/src/kwai/modules/club/members/value_objects.py rename to backend/src/kwai/modules/club/domain/value_objects.py index dd5e2058b..eda85759d 100644 --- a/backend/src/kwai/modules/club/members/value_objects.py +++ b/backend/src/kwai/modules/club/domain/value_objects.py @@ -4,7 +4,7 @@ from enum import Enum from kwai.core.domain.value_objects.date import Date -from kwai.modules.club.members.country import CountryEntity +from kwai.modules.club.domain.country import CountryEntity @dataclass(kw_only=True, frozen=True, slots=True) diff --git a/backend/src/kwai/modules/club/get_member.py b/backend/src/kwai/modules/club/get_member.py index 6959cb840..bd736c4e2 100644 --- a/backend/src/kwai/modules/club/get_member.py +++ b/backend/src/kwai/modules/club/get_member.py @@ -2,9 +2,10 @@ from dataclasses import dataclass +from kwai.core.domain.presenter import Presenter from kwai.core.domain.value_objects.unique_id import UniqueId -from kwai.modules.club.members.member import MemberEntity -from kwai.modules.club.members.member_repository import MemberRepository +from kwai.modules.club.domain.member import MemberEntity +from kwai.modules.club.repositories.member_repository import MemberRepository @dataclass(kw_only=True, frozen=True, slots=True) @@ -21,15 +22,17 @@ class GetMemberCommand: class GetMember: """Use case 'Get Member'.""" - def __init__(self, repo: MemberRepository): + def __init__(self, repo: MemberRepository, presenter: Presenter[MemberEntity]): """Initialize the use case. Args: repo: The repository used to get the member. + presenter: The presenter used to handle the result of the use case. """ self._repo = repo + self._presenter = presenter - async def execute(self, command: GetMemberCommand) -> MemberEntity: + async def execute(self, command: GetMemberCommand) -> None: """Execute the use case. Args: @@ -44,4 +47,5 @@ async def execute(self, command: GetMemberCommand) -> MemberEntity: query = self._repo.create_query() query.filter_by_uuid(UniqueId.create_from_string(command.uuid)) - return await self._repo.get(query) + member = await self._repo.get(query) + self._presenter.present(member) diff --git a/backend/src/kwai/modules/club/get_members.py b/backend/src/kwai/modules/club/get_members.py index 848841fb6..9172252ed 100644 --- a/backend/src/kwai/modules/club/get_members.py +++ b/backend/src/kwai/modules/club/get_members.py @@ -2,9 +2,10 @@ from dataclasses import dataclass -from kwai.core.domain.use_case import UseCaseBrowseResult +from kwai.core.domain.presenter import AsyncPresenter, IterableResult from kwai.core.domain.value_objects.date import Date -from kwai.modules.club.members.member_repository import MemberRepository +from kwai.modules.club.domain.member import MemberEntity +from kwai.modules.club.repositories.member_repository import MemberRepository @dataclass(kw_only=True, frozen=True, slots=True) @@ -29,15 +30,21 @@ class GetMembersCommand: class GetMembers: """Use case get members.""" - def __init__(self, repo: MemberRepository): + def __init__( + self, + repo: MemberRepository, + presenter: AsyncPresenter[IterableResult[MemberEntity]], + ): """Initialize use case. Args: repo: The repository for members. + presenter: The presenter for members. """ self._repo = repo + self._presenter = presenter - async def execute(self, command: GetMembersCommand) -> UseCaseBrowseResult: + async def execute(self, command: GetMembersCommand): """Execute the use case. Args: @@ -53,7 +60,11 @@ async def execute(self, command: GetMembersCommand) -> UseCaseBrowseResult: command.license_end_month, command.license_end_year or Date.today().year ) - return UseCaseBrowseResult( - count=await query.count(), - iterator=self._repo.get_all(query, command.limit, command.offset), + await self._presenter.present( + IterableResult( + count=await query.count(), + limit=command.limit, + offset=command.offset, + iterator=self._repo.get_all(query, command.limit, command.offset), + ) ) diff --git a/backend/src/kwai/modules/club/import_members.py b/backend/src/kwai/modules/club/import_members.py index e3ff5e088..3148acabe 100644 --- a/backend/src/kwai/modules/club/import_members.py +++ b/backend/src/kwai/modules/club/import_members.py @@ -2,22 +2,22 @@ from abc import ABC from dataclasses import dataclass -from typing import AsyncGenerator from kwai.core.domain.entity import Entity +from kwai.core.domain.presenter import Presenter from kwai.core.domain.use_case import UseCaseResult -from kwai.modules.club.members import member_importer -from kwai.modules.club.members.file_upload import FileUploadEntity -from kwai.modules.club.members.file_upload_repository import FileUploadRepository -from kwai.modules.club.members.member import MemberEntity -from kwai.modules.club.members.member_repository import ( +from kwai.modules.club.domain.file_upload import FileUploadEntity +from kwai.modules.club.domain.member import MemberEntity +from kwai.modules.club.repositories import member_importer +from kwai.modules.club.repositories.file_upload_repository import FileUploadRepository +from kwai.modules.club.repositories.member_repository import ( MemberNotFoundException, MemberRepository, ) @dataclass(kw_only=True, slots=True, frozen=True) -class Result(UseCaseResult, ABC): +class MemberImportResult(UseCaseResult, ABC): """The result of the use case ImportMembers.""" file_upload: FileUploadEntity @@ -25,7 +25,7 @@ class Result(UseCaseResult, ABC): @dataclass(kw_only=True, slots=True, frozen=True) -class OkResult(Result): +class OkMemberImportResult(MemberImportResult): """A successful import of a member.""" member: MemberEntity @@ -35,20 +35,20 @@ def to_message(self) -> str: @dataclass(kw_only=True, slots=True, frozen=True) -class FailureResult(Result): +class FailureMemberImportResult(MemberImportResult): """An import of a member failed.""" message: str def to_message(self) -> str: - return f"Import failed for row {self.row}: {self.message}." + return self.message @dataclass(kw_only=True, slots=True, frozen=True) class ImportMembersCommand: """Input for the use case "ImportMembers".""" - test: bool = True + preview: bool = True class ImportMembers: @@ -59,6 +59,7 @@ def __init__( importer: member_importer.MemberImporter, file_upload_repo: FileUploadRepository, member_repo: MemberRepository, + presenter: Presenter, ): """Initialize the use case. @@ -66,49 +67,57 @@ def __init__( importer: A class that is responsible for importing members from a resource. file_upload_repo: A repository for storing the file upload information. member_repo: A repository for managing members. + presenter: A presenter """ self._importer = importer self._file_upload_repo = file_upload_repo self._member_repo = member_repo + self._presenter = presenter - async def execute( - self, command: ImportMembersCommand - ) -> AsyncGenerator[Result, None]: - """Execute the use case. - - Yields: - OkResult: When the row was successfully imported. - FailureResult: When the row was not successfully imported. - """ + async def execute(self, command: ImportMembersCommand): + """Execute the use case.""" file_upload_entity = await self._file_upload_repo.create( - self._importer.create_file_upload_entity() + self._importer.create_file_upload_entity(command.preview) ) async for import_result in self._importer.import_(): match import_result: case member_importer.OkResult(): - member = await self._save_member(import_result.member, command.test) - yield OkResult( - file_upload=file_upload_entity, - row=import_result.row, - member=member, + member = await self._save_member( + file_upload_entity, import_result.member, command.preview + ) + self._presenter.present( + OkMemberImportResult( + file_upload=file_upload_entity, + row=import_result.row, + member=member, + ) ) case member_importer.FailureResult(): - yield FailureResult( - file_upload=file_upload_entity, - row=import_result.row, - message=import_result.message, + self._presenter.present( + FailureMemberImportResult( + file_upload=file_upload_entity, + row=import_result.row, + message=import_result.message, + ) ) + if not command.preview: + await self._activate_members(file_upload_entity) - async def _save_member(self, member: MemberEntity, test: bool) -> MemberEntity: + async def _save_member( + self, file_upload: FileUploadEntity, member: MemberEntity, preview: bool + ) -> MemberEntity: """Create or update the member.""" existing_member = await self._get_member(member) if existing_member is not None: updated_member = self._update_member(existing_member, member) - if not test: + if not preview: await self._member_repo.update(updated_member) + await self._file_upload_repo.save_member(file_upload, updated_member) return updated_member - if not test: - return await self._member_repo.create(member) + + if not preview: + member = await self._member_repo.create(member) + await self._file_upload_repo.save_member(file_upload, member) return member @classmethod @@ -154,3 +163,12 @@ async def _get_member(self, member: MemberEntity) -> MemberEntity | None: return None return member + + async def _activate_members(self, upload_entity: FileUploadEntity): + """Activate members. + + Members that are part of the upload will be activated. + Members not part of the upload will be deactivated. + """ + await self._member_repo.activate_members(upload_entity) + await self._member_repo.deactivate_members(upload_entity) diff --git a/backend/src/kwai/modules/club/members/__init__.py b/backend/src/kwai/modules/club/members/__init__.py deleted file mode 100644 index f103a4d4a..000000000 --- a/backend/src/kwai/modules/club/members/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Package for all modules related to members.""" diff --git a/backend/src/kwai/modules/club/repositories/__init__.py b/backend/src/kwai/modules/club/repositories/__init__.py new file mode 100644 index 000000000..c6660d92a --- /dev/null +++ b/backend/src/kwai/modules/club/repositories/__init__.py @@ -0,0 +1 @@ +"""Package for all the repositories.""" diff --git a/backend/src/kwai/modules/club/members/member_tables.py b/backend/src/kwai/modules/club/repositories/_tables.py similarity index 78% rename from backend/src/kwai/modules/club/members/member_tables.py rename to backend/src/kwai/modules/club/repositories/_tables.py index b2ceca2ce..0f73f56dd 100644 --- a/backend/src/kwai/modules/club/members/member_tables.py +++ b/backend/src/kwai/modules/club/repositories/_tables.py @@ -11,12 +11,13 @@ from kwai.core.domain.value_objects.timestamp import Timestamp from kwai.core.domain.value_objects.traceable_time import TraceableTime from kwai.core.domain.value_objects.unique_id import UniqueId -from kwai.modules.club.members.contact import ContactEntity, ContactIdentifier -from kwai.modules.club.members.country import CountryEntity, CountryIdentifier -from kwai.modules.club.members.file_upload import FileUploadEntity -from kwai.modules.club.members.member import MemberEntity, MemberIdentifier -from kwai.modules.club.members.person import PersonEntity, PersonIdentifier -from kwai.modules.club.members.value_objects import ( +from kwai.modules.club.domain.coach import CoachEntity +from kwai.modules.club.domain.contact import ContactEntity, ContactIdentifier +from kwai.modules.club.domain.country import CountryEntity, CountryIdentifier +from kwai.modules.club.domain.file_upload import FileUploadEntity +from kwai.modules.club.domain.member import MemberEntity, MemberIdentifier +from kwai.modules.club.domain.person import PersonEntity, PersonIdentifier +from kwai.modules.club.domain.value_objects import ( Address, Birthdate, Gender, @@ -90,6 +91,7 @@ class FileUploadRow(TableRow): uuid: str filename: str remark: str + preview: int user_id: int created_at: datetime updated_at: datetime | None @@ -106,6 +108,7 @@ def persist(cls, file_upload: FileUploadEntity) -> Self: uuid=str(file_upload.uuid), filename=file_upload.filename, remark=file_upload.remark, + preview=1 if file_upload.preview else 0, user_id=file_upload.owner.id.value, created_at=file_upload.traceable_time.created_at.timestamp, # type: ignore[arg-type] updated_at=file_upload.traceable_time.updated_at.timestamp, @@ -198,8 +201,8 @@ def create_entity( remark=self.remark or "", contact=contact, traceable_time=TraceableTime( - created_at=Timestamp(self.created_at), - updated_at=Timestamp(self.updated_at), + created_at=Timestamp.create_utc(self.created_at), + updated_at=Timestamp.create_utc(self.updated_at), ), nationality=nationality, ) @@ -253,8 +256,8 @@ def create_entity(self, person: PersonEntity) -> MemberEntity: active=self.active == 1, person=person, traceable_time=TraceableTime( - created_at=Timestamp(self.created_at), - updated_at=Timestamp(self.updated_at), + created_at=Timestamp.create_utc(self.created_at), + updated_at=Timestamp.create_utc(self.updated_at), ), ) @@ -273,3 +276,53 @@ def persist(cls, member: MemberEntity) -> Self: created_at=member.traceable_time.created_at.timestamp, # type: ignore[arg-type] updated_at=member.traceable_time.updated_at.timestamp, ) + + +@dataclass(kw_only=True, frozen=True, slots=True) +class MemberUploadRow(TableRow): + """Represents a row of the judo member imports table.""" + + __table_name__ = "judo_member_imports" + + member_id: int + import_id: int + created_at: datetime + + @classmethod + def persist(cls, upload: FileUploadEntity, member: MemberEntity) -> Self: + return cls( + member_id=member.id.value, + import_id=upload.id.value, + created_at=datetime.now(UTC), + ) + + +@dataclass(kw_only=True, frozen=True, slots=True) +class CoachRow(TableRow): + """Represents a row of the coach table.""" + + __table_name__ = "coaches" + + id: int + member_id: int + description: str + diploma: str + active: int + remark: str + user_id: int | None + created_at: datetime + updated_at: datetime | None + + @classmethod + def persist(cls, coach: CoachEntity) -> Self: + return cls( + id=coach.id.value, + member_id=coach.member.id.value, + description=coach.description, + diploma=coach.diploma, + active=1 if coach.is_active else 0, + remark=coach.remark, + user_id=None if coach.user is None else coach.user.id.value, + created_at=coach.traceable_time.created_at.timestamp, # type: ignore[arg-type] + updated_at=coach.traceable_time.updated_at.timestamp, + ) diff --git a/backend/src/kwai/modules/club/repositories/coach_db_repository.py b/backend/src/kwai/modules/club/repositories/coach_db_repository.py new file mode 100644 index 000000000..6bb325578 --- /dev/null +++ b/backend/src/kwai/modules/club/repositories/coach_db_repository.py @@ -0,0 +1,23 @@ +"""Module for defining a coach repository using a database.""" + +from kwai.core.db.database import Database +from kwai.core.domain.entity import Entity +from kwai.modules.club.domain.coach import CoachEntity, CoachIdentifier +from kwai.modules.club.repositories._tables import CoachRow +from kwai.modules.club.repositories.coach_repository import CoachRepository + + +class CoachDbRepository(CoachRepository): + """A coach repository using a database.""" + + def __init__(self, database: Database) -> None: + self._database = database + + async def create(self, coach: CoachEntity): + new_coach_id = await self._database.insert( + CoachRow.__table_name__, CoachRow.persist(coach) + ) + return Entity.replace(coach, id_=CoachIdentifier(new_coach_id)) + + async def delete(self, coach: CoachEntity): + await self._database.delete(coach.id.value, CoachRow.__table_name__) diff --git a/backend/src/kwai/modules/club/repositories/coach_repository.py b/backend/src/kwai/modules/club/repositories/coach_repository.py new file mode 100644 index 000000000..3f9e8ffc5 --- /dev/null +++ b/backend/src/kwai/modules/club/repositories/coach_repository.py @@ -0,0 +1,19 @@ +"""Module for defining an interface for a coach repository.""" + +from abc import ABC, abstractmethod + +from kwai.modules.club.domain.coach import CoachEntity + + +class CoachRepository(ABC): + """An interface for a coach repository.""" + + @abstractmethod + async def create(self, coach: CoachEntity): + """Save a new coach.""" + raise NotImplementedError + + @abstractmethod + async def delete(self, coach: CoachEntity): + """Delete an existing coach.""" + raise NotImplementedError diff --git a/backend/src/kwai/modules/club/members/contact_db_repository.py b/backend/src/kwai/modules/club/repositories/contact_db_repository.py similarity index 90% rename from backend/src/kwai/modules/club/members/contact_db_repository.py rename to backend/src/kwai/modules/club/repositories/contact_db_repository.py index 270e073d8..297dcf9d8 100644 --- a/backend/src/kwai/modules/club/members/contact_db_repository.py +++ b/backend/src/kwai/modules/club/repositories/contact_db_repository.py @@ -7,12 +7,12 @@ from kwai.core.db.database import Database from kwai.core.db.table_row import JoinedTableRow from kwai.core.domain.entity import Entity -from kwai.modules.club.members.contact import ContactEntity, ContactIdentifier -from kwai.modules.club.members.contact_repository import ( +from kwai.modules.club.domain.contact import ContactEntity, ContactIdentifier +from kwai.modules.club.repositories._tables import ContactRow, CountryRow +from kwai.modules.club.repositories.contact_repository import ( ContactNotFoundException, ContactRepository, ) -from kwai.modules.club.members.member_tables import ContactRow, CountryRow @dataclass(kw_only=True, frozen=True, slots=True) diff --git a/backend/src/kwai/modules/club/members/contact_repository.py b/backend/src/kwai/modules/club/repositories/contact_repository.py similarity index 90% rename from backend/src/kwai/modules/club/members/contact_repository.py rename to backend/src/kwai/modules/club/repositories/contact_repository.py index 11973b60b..39f0caab9 100644 --- a/backend/src/kwai/modules/club/members/contact_repository.py +++ b/backend/src/kwai/modules/club/repositories/contact_repository.py @@ -2,7 +2,7 @@ from abc import ABC, abstractmethod -from kwai.modules.club.members.contact import ContactEntity, ContactIdentifier +from kwai.modules.club.domain.contact import ContactEntity, ContactIdentifier class ContactNotFoundException(Exception): diff --git a/backend/src/kwai/modules/club/members/country_db_repository.py b/backend/src/kwai/modules/club/repositories/country_db_repository.py similarity index 86% rename from backend/src/kwai/modules/club/members/country_db_repository.py rename to backend/src/kwai/modules/club/repositories/country_db_repository.py index 02c7d678b..d578c3e5b 100644 --- a/backend/src/kwai/modules/club/members/country_db_repository.py +++ b/backend/src/kwai/modules/club/repositories/country_db_repository.py @@ -4,12 +4,12 @@ from kwai.core.db.database import Database from kwai.core.domain.entity import Entity -from kwai.modules.club.members.country import CountryEntity, CountryIdentifier -from kwai.modules.club.members.country_repository import ( +from kwai.modules.club.domain.country import CountryEntity, CountryIdentifier +from kwai.modules.club.repositories._tables import CountryRow +from kwai.modules.club.repositories.country_repository import ( CountryNotFoundException, CountryRepository, ) -from kwai.modules.club.members.member_tables import CountryRow class CountryDbRepository(CountryRepository): diff --git a/backend/src/kwai/modules/club/members/country_repository.py b/backend/src/kwai/modules/club/repositories/country_repository.py similarity index 91% rename from backend/src/kwai/modules/club/members/country_repository.py rename to backend/src/kwai/modules/club/repositories/country_repository.py index 1dcd08107..1584889b2 100644 --- a/backend/src/kwai/modules/club/members/country_repository.py +++ b/backend/src/kwai/modules/club/repositories/country_repository.py @@ -2,7 +2,7 @@ from abc import ABC, abstractmethod -from kwai.modules.club.members.country import CountryEntity +from kwai.modules.club.domain.country import CountryEntity class CountryNotFoundException(Exception): diff --git a/backend/src/kwai/modules/club/members/file_upload_db_repository.py b/backend/src/kwai/modules/club/repositories/file_upload_db_repository.py similarity index 58% rename from backend/src/kwai/modules/club/members/file_upload_db_repository.py rename to backend/src/kwai/modules/club/repositories/file_upload_db_repository.py index f6937b3c1..eb8b263ff 100644 --- a/backend/src/kwai/modules/club/members/file_upload_db_repository.py +++ b/backend/src/kwai/modules/club/repositories/file_upload_db_repository.py @@ -2,9 +2,10 @@ from kwai.core.db.database import Database from kwai.core.domain.entity import Entity -from kwai.modules.club.members.file_upload import FileUploadEntity, FileUploadIdentifier -from kwai.modules.club.members.file_upload_repository import FileUploadRepository -from kwai.modules.club.members.member_tables import FileUploadRow +from kwai.modules.club.domain.file_upload import FileUploadEntity, FileUploadIdentifier +from kwai.modules.club.domain.member import MemberEntity +from kwai.modules.club.repositories._tables import FileUploadRow, MemberUploadRow +from kwai.modules.club.repositories.file_upload_repository import FileUploadRepository class FileUploadDbRepository(FileUploadRepository): @@ -22,5 +23,10 @@ async def create(self, file_upload: FileUploadEntity) -> FileUploadEntity: new_id = await self._database.insert( FileUploadRow.__table_name__, FileUploadRow.persist(file_upload) ) - await self._database.commit() return Entity.replace(file_upload, id_=FileUploadIdentifier(new_id)) + + async def save_member(self, file_upload: FileUploadEntity, member: MemberEntity): + await self._database.insert( + MemberUploadRow.__table_name__, + MemberUploadRow.persist(file_upload, member), + ) diff --git a/backend/src/kwai/modules/club/members/file_upload_repository.py b/backend/src/kwai/modules/club/repositories/file_upload_repository.py similarity index 52% rename from backend/src/kwai/modules/club/members/file_upload_repository.py rename to backend/src/kwai/modules/club/repositories/file_upload_repository.py index a7fe55b95..5fe282b81 100644 --- a/backend/src/kwai/modules/club/members/file_upload_repository.py +++ b/backend/src/kwai/modules/club/repositories/file_upload_repository.py @@ -1,7 +1,9 @@ """Module that defines an interface for a file upload repository.""" + from abc import ABC, abstractmethod -from kwai.modules.club.members.file_upload import FileUploadEntity +from kwai.modules.club.domain.file_upload import FileUploadEntity +from kwai.modules.club.domain.member import MemberEntity class FileUploadRepository(ABC): @@ -18,3 +20,13 @@ async def create(self, file_upload: FileUploadEntity) -> FileUploadEntity: file_upload: A fileupload to save. """ raise NotImplementedError + + @abstractmethod + async def save_member(self, file_upload: FileUploadEntity, member: MemberEntity): + """Save a member imported from the file upload. + + Args: + file_upload: The file upload. + member: The member from the file upload. + """ + raise NotImplementedError diff --git a/backend/src/kwai/modules/club/members/flemish_member_importer.py b/backend/src/kwai/modules/club/repositories/flemish_member_importer.py similarity index 90% rename from backend/src/kwai/modules/club/members/flemish_member_importer.py rename to backend/src/kwai/modules/club/repositories/flemish_member_importer.py index 82540f834..6a453640a 100644 --- a/backend/src/kwai/modules/club/members/flemish_member_importer.py +++ b/backend/src/kwai/modules/club/repositories/flemish_member_importer.py @@ -10,20 +10,20 @@ ) from kwai.core.domain.value_objects.name import Name from kwai.core.domain.value_objects.owner import Owner -from kwai.modules.club.members.contact import ContactEntity -from kwai.modules.club.members.country_repository import ( +from kwai.modules.club.domain.contact import ContactEntity +from kwai.modules.club.domain.member import MemberEntity +from kwai.modules.club.domain.person import PersonEntity +from kwai.modules.club.domain.value_objects import Address, Birthdate, Gender, License +from kwai.modules.club.repositories.country_repository import ( CountryNotFoundException, CountryRepository, ) -from kwai.modules.club.members.member import MemberEntity -from kwai.modules.club.members.member_importer import ( +from kwai.modules.club.repositories.member_importer import ( FailureResult, MemberImporter, OkResult, Result, ) -from kwai.modules.club.members.person import PersonEntity -from kwai.modules.club.members.value_objects import Address, Birthdate, Gender, License class FlemishMemberImporter(MemberImporter): @@ -68,7 +68,7 @@ async def import_(self) -> AsyncGenerator[Result, None]: emails = [] try: for email in row["email"].split(";"): - emails.append(EmailAddress(email)) + emails.append(EmailAddress(email.strip())) except InvalidEmailException as exc: yield FailureResult(row=row_index, message=str(exc)) continue diff --git a/backend/src/kwai/modules/club/members/member_db_query.py b/backend/src/kwai/modules/club/repositories/member_db_query.py similarity index 94% rename from backend/src/kwai/modules/club/members/member_db_query.py rename to backend/src/kwai/modules/club/repositories/member_db_query.py index 55ab71296..b6aa4f591 100644 --- a/backend/src/kwai/modules/club/members/member_db_query.py +++ b/backend/src/kwai/modules/club/repositories/member_db_query.py @@ -9,14 +9,14 @@ from kwai.core.db.database_query import DatabaseQuery from kwai.core.db.table_row import JoinedTableRow from kwai.core.domain.value_objects.unique_id import UniqueId -from kwai.modules.club.members.member import MemberEntity, MemberIdentifier -from kwai.modules.club.members.member_query import MemberQuery -from kwai.modules.club.members.member_tables import ( +from kwai.modules.club.domain.member import MemberEntity, MemberIdentifier +from kwai.modules.club.repositories._tables import ( ContactRow, CountryRow, MemberRow, PersonRow, ) +from kwai.modules.club.repositories.member_query import MemberQuery @dataclass(kw_only=True, frozen=True, slots=True) diff --git a/backend/src/kwai/modules/club/members/member_db_repository.py b/backend/src/kwai/modules/club/repositories/member_db_repository.py similarity index 57% rename from backend/src/kwai/modules/club/members/member_db_repository.py rename to backend/src/kwai/modules/club/repositories/member_db_repository.py index 07d08d34f..05cfefcf7 100644 --- a/backend/src/kwai/modules/club/members/member_db_repository.py +++ b/backend/src/kwai/modules/club/repositories/member_db_repository.py @@ -2,17 +2,20 @@ from typing import AsyncGenerator +from sql_smith.functions import field + from kwai.core.db.database import Database from kwai.core.domain.entity import Entity -from kwai.modules.club.members.member import MemberEntity, MemberIdentifier -from kwai.modules.club.members.member_db_query import MemberDbQuery, MemberQueryRow -from kwai.modules.club.members.member_query import MemberQuery -from kwai.modules.club.members.member_repository import ( +from kwai.modules.club.domain.file_upload import FileUploadEntity +from kwai.modules.club.domain.member import MemberEntity, MemberIdentifier +from kwai.modules.club.repositories._tables import MemberRow, MemberUploadRow +from kwai.modules.club.repositories.member_db_query import MemberDbQuery, MemberQueryRow +from kwai.modules.club.repositories.member_query import MemberQuery +from kwai.modules.club.repositories.member_repository import ( MemberNotFoundException, MemberRepository, ) -from kwai.modules.club.members.member_tables import MemberRow -from kwai.modules.club.members.person_db_repository import PersonDbRepository +from kwai.modules.club.repositories.person_db_repository import PersonDbRepository class MemberDbRepository(MemberRepository): @@ -70,3 +73,31 @@ async def update(self, member: MemberEntity) -> None: async def delete(self, member: MemberEntity) -> None: await PersonDbRepository(self._database).delete(member.person) await self._database.delete(member.id, MemberRow.__table_name__) + + async def activate_members(self, upload: FileUploadEntity) -> None: + member_upload_query = ( + self._database.create_query_factory() + .select("member_id") + .from_(MemberUploadRow.__table_name__) + .where(field("import_id").eq(upload.id.value)) + ) + update_query = ( + self._database.create_query_factory() + .update(MemberRow.__table_name__, {"active": 1}) + .where(field("id").in_(member_upload_query)) + ) + await self._database.execute(update_query) + + async def deactivate_members(self, upload: FileUploadEntity) -> None: + member_upload_query = ( + self._database.create_query_factory() + .select("member_id") + .from_(MemberUploadRow.__table_name__) + .where(field("import_id").eq(upload.id.value)) + ) + update_query = ( + self._database.create_query_factory() + .update(MemberRow.__table_name__, {"active": 0}) + .where(field("id").not_in(member_upload_query)) + ) + await self._database.execute(update_query) diff --git a/backend/src/kwai/modules/club/members/member_importer.py b/backend/src/kwai/modules/club/repositories/member_importer.py similarity index 80% rename from backend/src/kwai/modules/club/members/member_importer.py rename to backend/src/kwai/modules/club/repositories/member_importer.py index a4e1007e4..e1e85a181 100644 --- a/backend/src/kwai/modules/club/members/member_importer.py +++ b/backend/src/kwai/modules/club/repositories/member_importer.py @@ -7,10 +7,10 @@ from async_lru import alru_cache from kwai.core.domain.value_objects.owner import Owner -from kwai.modules.club.members.country import CountryEntity -from kwai.modules.club.members.country_repository import CountryRepository -from kwai.modules.club.members.file_upload import FileUploadEntity -from kwai.modules.club.members.member import MemberEntity +from kwai.modules.club.domain.country import CountryEntity +from kwai.modules.club.domain.file_upload import FileUploadEntity +from kwai.modules.club.domain.member import MemberEntity +from kwai.modules.club.repositories.country_repository import CountryRepository @dataclass(kw_only=True, frozen=True, slots=True) @@ -56,9 +56,11 @@ def import_(self) -> AsyncGenerator[Result, None]: For each imported (or failed import) of a member, a result will be yielded. """ - def create_file_upload_entity(self) -> FileUploadEntity: + def create_file_upload_entity(self, preview: bool) -> FileUploadEntity: """Create a file upload entity.""" - return FileUploadEntity(filename=self._filename, owner=self._owner) + return FileUploadEntity( + filename=self._filename, owner=self._owner, preview=preview + ) @staticmethod @alru_cache diff --git a/backend/src/kwai/modules/club/members/member_query.py b/backend/src/kwai/modules/club/repositories/member_query.py similarity index 93% rename from backend/src/kwai/modules/club/members/member_query.py rename to backend/src/kwai/modules/club/repositories/member_query.py index 3d27e6dd5..bcd4e72d8 100644 --- a/backend/src/kwai/modules/club/members/member_query.py +++ b/backend/src/kwai/modules/club/repositories/member_query.py @@ -5,7 +5,7 @@ from kwai.core.domain.repository.query import Query from kwai.core.domain.value_objects.unique_id import UniqueId -from kwai.modules.club.members.member import MemberIdentifier +from kwai.modules.club.domain.member import MemberIdentifier class MemberQuery(Query, ABC): diff --git a/backend/src/kwai/modules/club/members/member_repository.py b/backend/src/kwai/modules/club/repositories/member_repository.py similarity index 75% rename from backend/src/kwai/modules/club/members/member_repository.py rename to backend/src/kwai/modules/club/repositories/member_repository.py index c1bf81cea..2cfb33d8e 100644 --- a/backend/src/kwai/modules/club/members/member_repository.py +++ b/backend/src/kwai/modules/club/repositories/member_repository.py @@ -3,8 +3,9 @@ from abc import ABC, abstractmethod from typing import AsyncGenerator -from kwai.modules.club.members.member import MemberEntity -from kwai.modules.club.members.member_query import MemberQuery +from kwai.modules.club.domain.file_upload import FileUploadEntity +from kwai.modules.club.domain.member import MemberEntity +from kwai.modules.club.repositories.member_query import MemberQuery class MemberNotFoundException(Exception): @@ -27,7 +28,7 @@ async def get(self, query: MemberQuery | None = None) -> MemberEntity: query: The query to use for getting the first member. Raises: - MemberNotFoundException + MemberNotFoundException: Raised when the member is not found. """ raise NotImplementedError @@ -79,3 +80,13 @@ async def delete(self, member: MemberEntity) -> None: member: The member to delete. """ raise NotImplementedError + + @abstractmethod + async def activate_members(self, upload: FileUploadEntity) -> None: + """Activate all members that have been uploaded.""" + raise NotImplementedError + + @abstractmethod + async def deactivate_members(self, upload: FileUploadEntity) -> None: + """Deactivate all members that are not being uploaded.""" + raise NotImplementedError diff --git a/backend/src/kwai/modules/club/members/person_db_repository.py b/backend/src/kwai/modules/club/repositories/person_db_repository.py similarity index 89% rename from backend/src/kwai/modules/club/members/person_db_repository.py rename to backend/src/kwai/modules/club/repositories/person_db_repository.py index eb55a89b4..a61364eb9 100644 --- a/backend/src/kwai/modules/club/members/person_db_repository.py +++ b/backend/src/kwai/modules/club/repositories/person_db_repository.py @@ -7,10 +7,14 @@ from kwai.core.db.database import Database from kwai.core.db.table_row import JoinedTableRow from kwai.core.domain.entity import Entity -from kwai.modules.club.members.contact_db_repository import ContactDbRepository -from kwai.modules.club.members.member_tables import ContactRow, CountryRow, PersonRow -from kwai.modules.club.members.person import PersonEntity, PersonIdentifier -from kwai.modules.club.members.person_repository import ( +from kwai.modules.club.domain.person import PersonEntity, PersonIdentifier +from kwai.modules.club.repositories._tables import ( + ContactRow, + CountryRow, + PersonRow, +) +from kwai.modules.club.repositories.contact_db_repository import ContactDbRepository +from kwai.modules.club.repositories.person_repository import ( PersonNotFoundException, PersonRepository, ) diff --git a/backend/src/kwai/modules/club/members/person_repository.py b/backend/src/kwai/modules/club/repositories/person_repository.py similarity index 90% rename from backend/src/kwai/modules/club/members/person_repository.py rename to backend/src/kwai/modules/club/repositories/person_repository.py index d5de5d4f5..6f81ecfe3 100644 --- a/backend/src/kwai/modules/club/members/person_repository.py +++ b/backend/src/kwai/modules/club/repositories/person_repository.py @@ -2,7 +2,7 @@ from abc import ABC, abstractmethod -from kwai.modules.club.members.person import PersonEntity, PersonIdentifier +from kwai.modules.club.domain.person import PersonEntity, PersonIdentifier class PersonNotFoundException(Exception): diff --git a/backend/src/kwai/modules/identity/authenticate_user.py b/backend/src/kwai/modules/identity/authenticate_user.py index 919fa4c2a..bcb7c998f 100644 --- a/backend/src/kwai/modules/identity/authenticate_user.py +++ b/backend/src/kwai/modules/identity/authenticate_user.py @@ -1,8 +1,9 @@ """Module that implements the use case: authenticate user.""" + from dataclasses import dataclass -from datetime import datetime, timedelta from kwai.core.domain.value_objects.email_address import EmailAddress +from kwai.core.domain.value_objects.timestamp import Timestamp from kwai.modules.identity.exceptions import AuthenticationException from kwai.modules.identity.tokens.access_token import AccessTokenEntity from kwai.modules.identity.tokens.access_token_repository import AccessTokenRepository @@ -87,8 +88,9 @@ async def execute(self, command: AuthenticateUserCommand) -> RefreshTokenEntity: access_token = await self._access_token_repo.create( AccessTokenEntity( identifier=TokenIdentifier.generate(), - expiration=datetime.utcnow() - + timedelta(minutes=command.access_token_expiry_minutes), + expiration=Timestamp.create_with_delta( + minutes=command.access_token_expiry_minutes + ), user_account=user_account, ) ) @@ -96,8 +98,9 @@ async def execute(self, command: AuthenticateUserCommand) -> RefreshTokenEntity: return await self._refresh_token_repo.create( RefreshTokenEntity( identifier=TokenIdentifier.generate(), - expiration=datetime.utcnow() - + timedelta(minutes=command.refresh_token_expiry_minutes), + expiration=Timestamp.create_with_delta( + minutes=command.refresh_token_expiry_minutes + ), access_token=access_token, ) ) diff --git a/backend/src/kwai/modules/identity/refresh_access_token.py b/backend/src/kwai/modules/identity/refresh_access_token.py index 1814cec26..1265af7d4 100644 --- a/backend/src/kwai/modules/identity/refresh_access_token.py +++ b/backend/src/kwai/modules/identity/refresh_access_token.py @@ -1,7 +1,8 @@ """Module that defines the use case for refreshing an access token.""" + from dataclasses import dataclass -from datetime import datetime, timedelta +from kwai.core.domain.value_objects.timestamp import Timestamp from kwai.modules.identity.authenticate_user import AuthenticationException from kwai.modules.identity.tokens.access_token import AccessTokenEntity from kwai.modules.identity.tokens.access_token_repository import AccessTokenRepository @@ -82,8 +83,9 @@ async def execute(self, command: RefreshAccessTokenCommand) -> RefreshTokenEntit access_token = await self._access_token_repo.create( AccessTokenEntity( identifier=TokenIdentifier.generate(), - expiration=datetime.utcnow() - + timedelta(minutes=command.access_token_expiry_minutes), + expiration=Timestamp.create_with_delta( + minutes=command.access_token_expiry_minutes + ), user_account=refresh_token.access_token.user_account, ) ) @@ -91,8 +93,9 @@ async def execute(self, command: RefreshAccessTokenCommand) -> RefreshTokenEntit return await self._refresh_token_repo.create( RefreshTokenEntity( identifier=TokenIdentifier.generate(), - expiration=datetime.utcnow() - + timedelta(minutes=command.refresh_token_expiry_minutes), + expiration=Timestamp.create_with_delta( + minutes=command.refresh_token_expiry_minutes + ), access_token=access_token, ) ) diff --git a/backend/src/kwai/modules/identity/tokens/access_token.py b/backend/src/kwai/modules/identity/tokens/access_token.py index cea3c6e6d..c208ef71b 100644 --- a/backend/src/kwai/modules/identity/tokens/access_token.py +++ b/backend/src/kwai/modules/identity/tokens/access_token.py @@ -1,8 +1,8 @@ """Module that defines an access token entity.""" -from datetime import datetime from kwai.core.domain.entity import Entity from kwai.core.domain.value_objects.identifier import IntIdentifier +from kwai.core.domain.value_objects.timestamp import Timestamp from kwai.core.domain.value_objects.traceable_time import TraceableTime from kwai.modules.identity.tokens.token_identifier import TokenIdentifier from kwai.modules.identity.users.user_account import UserAccountEntity @@ -19,26 +19,26 @@ def __init__( id_: AccessTokenIdentifier | None = None, user_account: UserAccountEntity, identifier: TokenIdentifier | None = None, - expiration: datetime | None = None, + expiration: Timestamp | None = None, revoked: bool = False, traceable_time: TraceableTime | None = None, ): super().__init__(id_ or AccessTokenIdentifier()) self._user_account = user_account self._identifier = identifier or TokenIdentifier.generate() - self._expiration = expiration or datetime.utcnow() + self._expiration = expiration or Timestamp.create_now() self._revoked = revoked self._traceable_time = traceable_time or TraceableTime() @property - def expiration(self) -> datetime: + def expiration(self) -> Timestamp: """Return the expiration timestamp of the access token.""" return self._expiration @property def expired(self) -> bool: """Return true when the access token is expired.""" - return self._expiration < datetime.utcnow() + return self._expiration.is_past @property def identifier(self) -> TokenIdentifier: diff --git a/backend/src/kwai/modules/identity/tokens/refresh_token.py b/backend/src/kwai/modules/identity/tokens/refresh_token.py index b7f02907a..72cca7245 100644 --- a/backend/src/kwai/modules/identity/tokens/refresh_token.py +++ b/backend/src/kwai/modules/identity/tokens/refresh_token.py @@ -1,8 +1,8 @@ """Module for a refresh token entity.""" -from datetime import datetime from kwai.core.domain.entity import Entity from kwai.core.domain.value_objects.identifier import IntIdentifier +from kwai.core.domain.value_objects.timestamp import Timestamp from kwai.core.domain.value_objects.traceable_time import TraceableTime from kwai.modules.identity.tokens.access_token import AccessTokenEntity from kwai.modules.identity.tokens.token_identifier import TokenIdentifier @@ -19,14 +19,14 @@ def __init__( id_: RefreshTokenIdentifier | None = None, access_token: AccessTokenEntity, identifier: TokenIdentifier | None = None, - expiration: datetime | None, + expiration: Timestamp | None, revoked: bool = False, traceable_time: TraceableTime | None = None, ): super().__init__(id_ or RefreshTokenIdentifier()) self._access_token = access_token self._identifier = identifier or TokenIdentifier.generate() - self._expiration = expiration or datetime.utcnow() + self._expiration = expiration or Timestamp.create_now() self._revoked = revoked self._traceable_time = traceable_time or TraceableTime() @@ -36,14 +36,14 @@ def access_token(self) -> AccessTokenEntity: return self._access_token @property - def expiration(self) -> datetime: + def expiration(self) -> Timestamp: """Return the expiration timestamp of the refresh token.""" return self._expiration @property def expired(self) -> bool: """Return True when the token is expired.""" - return self._expiration < datetime.utcnow() + return self._expiration.is_past @property def identifier(self) -> TokenIdentifier: diff --git a/backend/src/kwai/modules/identity/tokens/token_tables.py b/backend/src/kwai/modules/identity/tokens/token_tables.py index 0ae02cbb4..1303b3346 100644 --- a/backend/src/kwai/modules/identity/tokens/token_tables.py +++ b/backend/src/kwai/modules/identity/tokens/token_tables.py @@ -35,12 +35,12 @@ def create_entity(self, user_account: UserAccountEntity) -> AccessTokenEntity: return AccessTokenEntity( id_=AccessTokenIdentifier(self.id), identifier=TokenIdentifier(hex_string=self.identifier), - expiration=self.expiration, + expiration=Timestamp.create_utc(self.expiration), user_account=user_account, revoked=self.revoked, traceable_time=TraceableTime( - created_at=Timestamp(timestamp=self.created_at), - updated_at=Timestamp(timestamp=self.updated_at), + created_at=Timestamp.create_utc(self.created_at), + updated_at=Timestamp.create_utc(self.updated_at), ), ) @@ -50,7 +50,7 @@ def persist(cls, access_token: AccessTokenEntity) -> "AccessTokenRow": return AccessTokenRow( id=access_token.id.value, identifier=str(access_token.identifier), - expiration=access_token.expiration, + expiration=access_token.expiration.timestamp, user_id=access_token.user_account.id.value, revoked=access_token.revoked, created_at=access_token.traceable_time.created_at.timestamp, @@ -79,11 +79,11 @@ def create_entity(self, access_token: AccessTokenEntity) -> RefreshTokenEntity: id_=RefreshTokenIdentifier(self.id), identifier=TokenIdentifier(hex_string=self.identifier), access_token=access_token, - expiration=self.expiration, + expiration=Timestamp.create_utc(self.expiration), revoked=self.revoked, traceable_time=TraceableTime( - created_at=Timestamp(timestamp=self.created_at), - updated_at=Timestamp(timestamp=self.updated_at), + created_at=Timestamp.create_utc(self.created_at), + updated_at=Timestamp.create_utc(self.updated_at), ), ) @@ -94,7 +94,7 @@ def persist(cls, refresh_token: RefreshTokenEntity) -> "RefreshTokenRow": id=refresh_token.id.value, identifier=str(refresh_token.identifier), access_token_id=refresh_token.access_token.id.value, - expiration=refresh_token.expiration, + expiration=refresh_token.expiration.timestamp, revoked=refresh_token.revoked, created_at=refresh_token.traceable_time.created_at.timestamp, updated_at=refresh_token.traceable_time.updated_at.timestamp, diff --git a/backend/src/kwai/modules/identity/user_invitations/user_invitation_query.py b/backend/src/kwai/modules/identity/user_invitations/user_invitation_query.py index 12c73ed76..df618b1fb 100644 --- a/backend/src/kwai/modules/identity/user_invitations/user_invitation_query.py +++ b/backend/src/kwai/modules/identity/user_invitations/user_invitation_query.py @@ -18,10 +18,10 @@ def filter_by_id(self, id_: UserInvitationIdentifier) -> "UserInvitationQuery": """Add a filter on the user invitation for id. Args: - id_(UserInvitationIdentifier): An id of a user invitation. + id_: An id of a user invitation. Returns: - (UserInvitationQuery): The active query + The active query """ raise NotImplementedError @@ -29,10 +29,10 @@ def filter_by_uuid(self, uuid: UniqueId) -> "UserInvitationQuery": """Add a filter on the user invitation for the unique id. Args: - uuid(UniqueId): A unique id of a user invitation. + uuid: A unique id of a user invitation. Returns: - (UserInvitationQuery): The active query + The active query """ raise NotImplementedError diff --git a/backend/src/kwai/modules/identity/user_invitations/user_invitation_repository.py b/backend/src/kwai/modules/identity/user_invitations/user_invitation_repository.py index aa30b88ca..89b65ff2a 100644 --- a/backend/src/kwai/modules/identity/user_invitations/user_invitation_repository.py +++ b/backend/src/kwai/modules/identity/user_invitations/user_invitation_repository.py @@ -1,4 +1,5 @@ """Module that defines an interface for an invitation repository.""" + from abc import ABC, abstractmethod from typing import AsyncIterator @@ -54,7 +55,7 @@ async def get_invitation_by_id( """Get an invitation using the id. Args: - id_(UserInvitationIdentifier): The id of the invitation to search for. + id_: The id of the invitation to search for. """ raise NotImplementedError @@ -63,7 +64,7 @@ async def get_invitation_by_uuid(self, uuid: UniqueId) -> UserInvitationEntity: """Get an invitation using the unique id. Args: - uuid(UniqueId): The unique id to use for searching the invitation. + uuid: The unique id to use for searching the invitation. """ raise NotImplementedError @@ -72,7 +73,7 @@ async def create(self, invitation: UserInvitationEntity) -> UserInvitationEntity """Create a new invitation. Args: - invitation(UserInvitationEntity): The invitation to create. + invitation: The invitation to create. """ raise NotImplementedError @@ -81,7 +82,7 @@ async def update(self, invitation: UserInvitationEntity) -> None: """Update an existing invitation. Args: - invitation(UserInvitationEntity): The invitation to update. + invitation: The invitation to update. """ raise NotImplementedError @@ -90,6 +91,6 @@ async def delete(self, invitation: UserInvitationEntity) -> None: """Delete the invitation. Args: - invitation(UserInvitationEntity): The invitation to delete. + invitation: The invitation to delete. """ raise NotImplementedError diff --git a/backend/src/kwai/modules/identity/user_invitations/user_invitation_tables.py b/backend/src/kwai/modules/identity/user_invitations/user_invitation_tables.py index 45d8697b2..ac1c5f8f9 100644 --- a/backend/src/kwai/modules/identity/user_invitations/user_invitation_tables.py +++ b/backend/src/kwai/modules/identity/user_invitations/user_invitation_tables.py @@ -54,25 +54,25 @@ def create_entity(self, user: UserEntity) -> UserInvitationEntity: """Create a user invitation entity from the table row. Args: - user(UserEntity): The associated user entity + user: The associated user entity Returns: - (UserInvitationEntity) + A user invitation entity. """ return UserInvitationEntity( id_=UserInvitationIdentifier(self.id), email=EmailAddress(self.email), name=Name(last_name=self.last_name, first_name=self.first_name), uuid=UniqueId.create_from_string(self.uuid), - expired_at=Timestamp(self.expired_at), + expired_at=Timestamp.create_utc(self.expired_at), user=user, remark=self.remark or "", - mailed_at=Timestamp(self.mailed_at), - confirmed_at=Timestamp(self.confirmed_at), + mailed_at=Timestamp.create_utc(self.mailed_at), + confirmed_at=Timestamp.create_utc(self.confirmed_at), revoked=self.revoked == 1, traceable_time=TraceableTime( - created_at=Timestamp(self.created_at), - updated_at=Timestamp(self.updated_at), + created_at=Timestamp.create_utc(self.created_at), + updated_at=Timestamp.create_utc(self.updated_at), ), ) @@ -81,10 +81,10 @@ def persist(cls, invitation: UserInvitationEntity) -> "UserInvitationRow": """Persist a user invitation entity into a table row. Args: - invitation(UserInvitationEntity): The user invitation entity to persist. + invitation: The user invitation entity to persist. Returns: - (UserInvitationRow): A dataclass containing the table row data. + A dataclass containing the table row data. """ return UserInvitationRow( id=invitation.id.value, diff --git a/backend/src/kwai/modules/identity/user_recoveries/user_recovery_tables.py b/backend/src/kwai/modules/identity/user_recoveries/user_recovery_tables.py index 0bbb57958..8f71718c5 100644 --- a/backend/src/kwai/modules/identity/user_recoveries/user_recovery_tables.py +++ b/backend/src/kwai/modules/identity/user_recoveries/user_recovery_tables.py @@ -34,13 +34,13 @@ def create_entity(self, user: UserEntity) -> UserRecoveryEntity: id_=UserRecoveryIdentifier(self.id), uuid=UniqueId.create_from_string(self.uuid), user=user, - expiration=Timestamp(self.expired_at), + expiration=Timestamp.create_utc(self.expired_at), remark=self.remark, - confirmation=Timestamp(self.confirmed_at), - mailed_at=Timestamp(self.mailed_at), + confirmation=Timestamp.create_utc(self.confirmed_at), + mailed_at=Timestamp.create_utc(self.mailed_at), traceable_time=TraceableTime( - created_at=Timestamp(timestamp=self.created_at), - updated_at=Timestamp(timestamp=self.updated_at), + created_at=Timestamp.create_utc(timestamp=self.created_at), + updated_at=Timestamp.create_utc(timestamp=self.updated_at), ), ) diff --git a/backend/src/kwai/modules/identity/users/user_account.py b/backend/src/kwai/modules/identity/users/user_account.py index 42a1666a8..d783af931 100644 --- a/backend/src/kwai/modules/identity/users/user_account.py +++ b/backend/src/kwai/modules/identity/users/user_account.py @@ -54,7 +54,7 @@ def login(self, password: str) -> bool: When login fails, last_unsuccessful_login will be updated. Args: - password(str): The password. + password: The password. """ if self._password.verify(password): self._last_login = Timestamp.create_now() @@ -72,7 +72,7 @@ def reset_password(self, password: Password): """Reset the password of the user account. Args: - password(Password): The new password. + password: The new password. """ if self._revoked: raise NotAllowedException() diff --git a/backend/src/kwai/modules/identity/users/user_tables.py b/backend/src/kwai/modules/identity/users/user_tables.py index 013995d7c..0e7393ad5 100644 --- a/backend/src/kwai/modules/identity/users/user_tables.py +++ b/backend/src/kwai/modules/identity/users/user_tables.py @@ -43,8 +43,8 @@ def create_entity(self) -> UserEntity: remark=self.remark, email=EmailAddress(self.email), traceable_time=TraceableTime( - created_at=Timestamp(timestamp=self.created_at), - updated_at=Timestamp(timestamp=self.updated_at), + created_at=Timestamp.create_utc(timestamp=self.created_at), + updated_at=Timestamp.create_utc(timestamp=self.updated_at), ), ) @@ -104,8 +104,8 @@ def create_entity(self) -> UserAccountEntity: ), email=EmailAddress(self.email), traceable_time=TraceableTime( - created_at=Timestamp(self.created_at), - updated_at=Timestamp(self.updated_at), + created_at=Timestamp.create_utc(self.created_at), + updated_at=Timestamp.create_utc(self.updated_at), ), ), ) diff --git a/backend/src/kwai/modules/portal/applications/application_tables.py b/backend/src/kwai/modules/portal/applications/application_tables.py index cd8310e4e..af2d3e41d 100644 --- a/backend/src/kwai/modules/portal/applications/application_tables.py +++ b/backend/src/kwai/modules/portal/applications/application_tables.py @@ -25,7 +25,7 @@ class ApplicationRow: remark: a remark about the application news: does this application can contain news stories? pages: does this application can contain pages? - events does this application can contain events? + events: does this application can contain events? weight: a weight that can be used to order the applications created_at: the timestamp of creation updated_at: the timestamp of the last modification @@ -62,8 +62,8 @@ def create_entity(self) -> ApplicationEntity: events=self.events == 1, weight=self.weight, traceable_time=TraceableTime( - created_at=Timestamp(self.created_at), - updated_at=Timestamp(self.updated_at), + created_at=Timestamp.create_utc(self.created_at), + updated_at=Timestamp.create_utc(self.updated_at), ), ) diff --git a/backend/src/kwai/modules/portal/news/news_item_db_query.py b/backend/src/kwai/modules/portal/news/news_item_db_query.py index b7d165e21..bc1033518 100644 --- a/backend/src/kwai/modules/portal/news/news_item_db_query.py +++ b/backend/src/kwai/modules/portal/news/news_item_db_query.py @@ -1,5 +1,5 @@ """Module that implements a NewsItemQuery for a database.""" -from datetime import datetime + from typing import AsyncIterator from sql_smith.functions import criteria, express, func, group, literal, on @@ -7,6 +7,7 @@ from kwai.core.db.database import Database from kwai.core.db.database_query import DatabaseQuery from kwai.core.db.rows import OwnersTable +from kwai.core.domain.value_objects.timestamp import Timestamp from kwai.core.domain.value_objects.unique_id import UniqueId from kwai.modules.portal.applications.application_tables import ApplicationsTable from kwai.modules.portal.news.news_item import NewsItemIdentifier @@ -93,7 +94,7 @@ def filter_by_publication_date( return self def filter_by_promoted(self) -> "NewsItemQuery": - now = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S") + now = str(Timestamp.create_now()) condition = ( NewsItemsTable.field("promotion") .gt(0) @@ -118,7 +119,7 @@ def filter_by_application(self, application: int | str) -> "NewsItemQuery": return self def filter_by_active(self) -> "NewsItemQuery": - now = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S") + now = str(Timestamp.create_now()) self._query.and_where( group( NewsItemsTable.field("enabled") diff --git a/backend/src/kwai/modules/portal/news/news_tables.py b/backend/src/kwai/modules/portal/news/news_tables.py index b6e26e6bb..dbe983c91 100644 --- a/backend/src/kwai/modules/portal/news/news_tables.py +++ b/backend/src/kwai/modules/portal/news/news_tables.py @@ -88,18 +88,18 @@ def create_entity( enabled=self.enabled == 1, promotion=Promotion( priority=self.promotion, - end_date=Timestamp(self.promotion_end_date), + end_date=Timestamp.create_utc(self.promotion_end_date), ), period=Period( - start_date=Timestamp(self.publish_date), - end_date=Timestamp(self.end_date), + start_date=Timestamp.create_utc(self.publish_date), + end_date=Timestamp.create_utc(self.end_date), ), application=application, texts=texts, remark=self.remark or "", traceable_time=TraceableTime( - created_at=Timestamp(timestamp=self.created_at), - updated_at=Timestamp(timestamp=self.updated_at), + created_at=Timestamp.create_utc(timestamp=self.created_at), + updated_at=Timestamp.create_utc(timestamp=self.updated_at), ), ) diff --git a/backend/src/kwai/modules/portal/pages/page_tables.py b/backend/src/kwai/modules/portal/pages/page_tables.py index a1ff04c08..9613434ed 100644 --- a/backend/src/kwai/modules/portal/pages/page_tables.py +++ b/backend/src/kwai/modules/portal/pages/page_tables.py @@ -80,8 +80,8 @@ def create_entity( texts=content, remark=self.remark, traceable_time=TraceableTime( - created_at=Timestamp(timestamp=self.created_at), - updated_at=Timestamp(timestamp=self.updated_at), + created_at=Timestamp.create_utc(timestamp=self.created_at), + updated_at=Timestamp.create_utc(timestamp=self.updated_at), ), ) diff --git a/backend/src/kwai/modules/teams/__init__.py b/backend/src/kwai/modules/teams/__init__.py new file mode 100644 index 000000000..e805ce150 --- /dev/null +++ b/backend/src/kwai/modules/teams/__init__.py @@ -0,0 +1 @@ +"""Package for the teams module.""" diff --git a/backend/src/kwai/modules/teams/create_team.py b/backend/src/kwai/modules/teams/create_team.py new file mode 100644 index 000000000..f9e090c6f --- /dev/null +++ b/backend/src/kwai/modules/teams/create_team.py @@ -0,0 +1,37 @@ +"""Module that defines the use case 'Create Team'.""" + +from dataclasses import dataclass + +from kwai.core.domain.presenter import Presenter +from kwai.modules.teams.domain.team import TeamEntity +from kwai.modules.teams.repositories.team_repository import TeamRepository + + +@dataclass(kw_only=True, frozen=True, slots=True) +class CreateTeamCommand: + """Input for the use case 'Create Team'.""" + + name: str + active: bool + remark: str + + +class CreateTeam: + """Use case 'Create Team'.""" + + def __init__(self, team_repo: TeamRepository, presenter: Presenter[TeamEntity]): + """Initialize the use case. + + Args: + team_repo: A repository that creates the team. + presenter: A presenter for a team entity. + """ + self._team_repo = team_repo + self._presenter = presenter + + async def execute(self, command: CreateTeamCommand) -> None: + """Executes the use case.""" + team = TeamEntity( + name=command.name, active=command.active, remark=command.remark + ) + self._presenter.present(await self._team_repo.create(team)) diff --git a/backend/src/kwai/modules/teams/create_team_member.py b/backend/src/kwai/modules/teams/create_team_member.py new file mode 100644 index 000000000..b4f5485d2 --- /dev/null +++ b/backend/src/kwai/modules/teams/create_team_member.py @@ -0,0 +1,65 @@ +"""Module that defines the use case for creating a team member.""" + +from dataclasses import dataclass + +from kwai.core.domain.presenter import Presenter +from kwai.core.domain.value_objects.unique_id import UniqueId +from kwai.modules.teams.domain.team import TeamEntity, TeamIdentifier +from kwai.modules.teams.domain.team_member import TeamMember +from kwai.modules.teams.repositories.member_repository import MemberRepository +from kwai.modules.teams.repositories.team_repository import TeamRepository + + +@dataclass(frozen=True, kw_only=True, slots=True) +class CreateTeamMemberCommand: + """Input for the 'Create Team Member' use case.""" + + team_id: int + member_id: str + active: bool = True + + +class CreateTeamMember: + """Implements the 'Create Team Member' use case.""" + + def __init__( + self, + team_repository: TeamRepository, + member_repository: MemberRepository, + presenter: Presenter[tuple[TeamMember, TeamEntity]], + ): + """Initialize the use case. + + Args: + team_repository: A repository for retrieving the team. + member_repository: A repository for retrieving the member. + presenter: A Presenter for processing the result. + """ + self._team_repository = team_repository + self._member_repository = member_repository + self._presenter = presenter + + async def execute(self, command: CreateTeamMemberCommand) -> None: + """Execute the use case. + + Raises: + TeamNotFoundException: If the team does not exist. + MemberNotFoundException: If the member does not exist. + TeamMemberAlreadyExistException: If the member is already part of the team. + """ + team_query = self._team_repository.create_query().filter_by_id( + TeamIdentifier(command.team_id) + ) + team = await self._team_repository.get(team_query) + + member_query = self._member_repository.create_query().filter_by_uuid( + UniqueId.create_from_string(command.member_id) + ) + member = await self._member_repository.get(member_query) + + team_member = TeamMember(member=member, active=command.active) + team.add_member(team_member) + + await self._team_repository.add_team_member(team, team_member) + + self._presenter.present((team_member, team)) diff --git a/backend/src/kwai/modules/teams/delete_team.py b/backend/src/kwai/modules/teams/delete_team.py new file mode 100644 index 000000000..b8e59b95f --- /dev/null +++ b/backend/src/kwai/modules/teams/delete_team.py @@ -0,0 +1,40 @@ +"""Module that defines the use case "Delete Team".""" + +from dataclasses import dataclass + +from kwai.modules.teams.domain.team import TeamIdentifier +from kwai.modules.teams.repositories.team_repository import TeamRepository + + +@dataclass(kw_only=True, frozen=True, slots=True) +class DeleteTeamCommand: + """Input for the use case DeleteTeam.""" + + id: int + + +class DeleteTeam: + """Use case for deleting a team.""" + + def __init__(self, repo: TeamRepository): + """Initialize the use case. + + Args: + repo: A repository for deleting a team. + """ + self._repo = repo + + async def execute(self, command: DeleteTeamCommand) -> None: + """Execute the use case. + + Args: + command: The input for the use case. + + Raises: + TeamNotFoundException: If the team does not exist. + """ + team = await self._repo.get( + self._repo.create_query().filter_by_id(TeamIdentifier(command.id)) + ) + # TODO: check if the team is not attached to one or more trainings... + await self._repo.delete(team) diff --git a/backend/src/kwai/modules/teams/domain/__init__.py b/backend/src/kwai/modules/teams/domain/__init__.py new file mode 100644 index 000000000..cff765361 --- /dev/null +++ b/backend/src/kwai/modules/teams/domain/__init__.py @@ -0,0 +1 @@ +"""Package for domain models of the teams module.""" diff --git a/backend/src/kwai/modules/teams/domain/team.py b/backend/src/kwai/modules/teams/domain/team.py new file mode 100644 index 000000000..1d8ec98f6 --- /dev/null +++ b/backend/src/kwai/modules/teams/domain/team.py @@ -0,0 +1,77 @@ +"""Module for defining the team entity.""" + +from kwai.core.domain.entity import Entity +from kwai.core.domain.value_objects.identifier import IntIdentifier +from kwai.core.domain.value_objects.traceable_time import TraceableTime +from kwai.core.domain.value_objects.unique_id import UniqueId +from kwai.modules.teams.domain.team_member import TeamMember + +TeamIdentifier = IntIdentifier + + +class TeamMemberAlreadyExistException(Exception): + """Raised when the member is already part of the team.""" + + +class TeamEntity(Entity[TeamIdentifier]): + """Entity for a team of the club.""" + + def __init__( + self, + *, + id_: TeamIdentifier | None = None, + name: str, + active: bool = True, + remark: str = "", + members: dict[UniqueId, TeamMember] = None, + traceable_time: TraceableTime | None = None, + ): + super().__init__(id_ or TeamIdentifier()) + self._name = name + self._active = active + self._remark = remark + self._members = {} if members is None else members.copy() + self._traceable_time = traceable_time or TraceableTime() + + def __str__(self): + """Return string representation of the team entity.""" + return f"" + + def __repr__(self): + """Return representation of the team entity.""" + return f"<{self.__class__.__name__} id={self.id} name={self.name!r}>" + + @property + def name(self) -> str: + """Return the name of the team.""" + return self._name + + @property + def is_active(self): + """Is this team active?""" + return self._active + + @property + def remark(self) -> str: + """Return the remark of the team.""" + return self._remark + + @property + def traceable_time(self) -> TraceableTime: + """Return the traceable_time.""" + return self._traceable_time + + @property + def members(self) -> dict[UniqueId, TeamMember]: + """Return the members. + + Note: the returned list is a copy. + """ + return self._members.copy() + + def add_member(self, team_member: TeamMember): + if team_member.member.uuid in self._members: + raise TeamMemberAlreadyExistException( + f"Team member (id={team_member.member.id}) already part of team {self._name}" + ) + self._members[team_member.member.uuid] = team_member diff --git a/backend/src/kwai/modules/teams/domain/team_member.py b/backend/src/kwai/modules/teams/domain/team_member.py new file mode 100644 index 000000000..c92421cff --- /dev/null +++ b/backend/src/kwai/modules/teams/domain/team_member.py @@ -0,0 +1,98 @@ +"""Module for defining the team member entity.""" + +from dataclasses import dataclass + +from kwai.core.domain.entity import Entity +from kwai.core.domain.value_objects.identifier import IntIdentifier +from kwai.core.domain.value_objects.name import Name +from kwai.core.domain.value_objects.traceable_time import TraceableTime +from kwai.core.domain.value_objects.unique_id import UniqueId +from kwai.modules.club.domain.country import CountryEntity +from kwai.modules.club.domain.value_objects import Birthdate, Gender, License + +MemberIdentifier = IntIdentifier + + +class MemberEntity(Entity[MemberIdentifier]): + """A member entity. + + A member entity is an entity which holds specific information of a member + that can be used for a member of a team. + """ + + def __init__( + self, + *, + id_: MemberIdentifier, + uuid: UniqueId, + name: Name, + license: License, + birthdate: Birthdate, + nationality: CountryEntity, + gender: Gender, + active_in_club: bool = True, + ): + super().__init__(id_) + self._name = name + self._uuid = uuid + self._license = license + self._birthdate = birthdate + self._nationality = nationality + self._gender = gender + self._active_in_club = active_in_club + + def __str__(self) -> str: + """Return a string of this entity.""" + return f"{self._uuid} - {self._name}" + + def __repr__(self) -> str: + """Return a representation of this entity.""" + return f"<{self.__class__.__name__} id={self.id}, uuid={self.uuid}, name={self.name}>" + + @property + def name(self) -> Name: + """Return the name.""" + return self._name + + @property + def uuid(self) -> UniqueId: + """Return the uuid.""" + return self._uuid + + @property + def license(self) -> License: + """Return the license.""" + return self._license + + @property + def birthdate(self) -> Birthdate: + """Return the birthdate.""" + return self._birthdate + + @property + def nationality(self) -> CountryEntity: + """Return the nat.""" + return self._nationality + + @property + def gender(self) -> Gender: + """Return the gender.""" + return self._gender + + @property + def is_active_in_club(self) -> bool: + """Return if the member is active.""" + return self._active_in_club + + +@dataclass(kw_only=True, frozen=True, slots=True) +class TeamMember: + """Represent a member of a team. + + When active is False, it means the member is not active for the team it belongs + to. + """ + + active: bool = False + member: MemberEntity + traceable_time: TraceableTime = TraceableTime() diff --git a/backend/src/kwai/modules/teams/get_members.py b/backend/src/kwai/modules/teams/get_members.py new file mode 100644 index 000000000..997e1a3d6 --- /dev/null +++ b/backend/src/kwai/modules/teams/get_members.py @@ -0,0 +1,51 @@ +"""Module for defining the use case 'Get Members'.""" + +from dataclasses import dataclass + +from kwai.core.domain.presenter import AsyncPresenter, IterableResult +from kwai.modules.teams.domain.team import TeamIdentifier +from kwai.modules.teams.domain.team_member import MemberEntity +from kwai.modules.teams.repositories.member_repository import MemberRepository + + +@dataclass(frozen=True, kw_only=True, slots=True) +class GetMembersCommand: + """Input for the use case 'Get Members'. + + When in_team is False and a team_id is set, only the members that are not + part of that team will be returned. + """ + + team_id: int | None = None + in_team: bool = True + limit: int | None = None + offset: int | None = None + + +class GetMembers: + """Implements the use case 'Get Members'.""" + + def __init__( + self, + member_repository: MemberRepository, + presenter: AsyncPresenter[IterableResult[MemberEntity]], + ): + """Initialize the use case.""" + self._member_repository = member_repository + self._presenter = presenter + + async def execute(self, command: GetMembersCommand): + """Execute the use case.""" + member_query = self._member_repository.create_query() + if command.team_id is not None: + member_query = member_query.filter_by_team( + TeamIdentifier(command.team_id), command.in_team + ) + await self._presenter.present( + IterableResult( + count=await member_query.count(), + limit=command.limit, + offset=command.offset, + iterator=self._member_repository.get_all(member_query), + ) + ) diff --git a/backend/src/kwai/modules/teams/get_team.py b/backend/src/kwai/modules/teams/get_team.py new file mode 100644 index 000000000..9fff9c6c7 --- /dev/null +++ b/backend/src/kwai/modules/teams/get_team.py @@ -0,0 +1,33 @@ +"""Module that implements the use case 'Get Team'.""" + +from dataclasses import dataclass + +from kwai.core.domain.presenter import Presenter +from kwai.modules.teams.domain.team import TeamEntity, TeamIdentifier +from kwai.modules.teams.repositories.team_repository import TeamRepository + + +@dataclass(kw_only=True, frozen=True, slots=True) +class GetTeamCommand: + """Input for the use case 'Get Team'.""" + + id: int + + +class GetTeam: + """Implement the use case 'Get Teams'.""" + + def __init__( + self, + team_repo: TeamRepository, + presenter: Presenter[TeamEntity], + ): + """Initialize the use case.""" + self._team_repo = team_repo + self._presenter = presenter + + async def execute(self, command: GetTeamCommand) -> None: + """Execute the use case.""" + query = self._team_repo.create_query() + query.filter_by_id(TeamIdentifier(command.id)) + self._presenter.present(await self._team_repo.get(query)) diff --git a/backend/src/kwai/modules/teams/get_teams.py b/backend/src/kwai/modules/teams/get_teams.py new file mode 100644 index 000000000..5bb7d91b7 --- /dev/null +++ b/backend/src/kwai/modules/teams/get_teams.py @@ -0,0 +1,40 @@ +"""Module that implements the use case 'Get Teams'.""" + +from dataclasses import dataclass + +from kwai.core.domain.presenter import AsyncPresenter, IterableResult +from kwai.modules.teams.domain.team import TeamEntity +from kwai.modules.teams.repositories.team_repository import TeamRepository + + +@dataclass(kw_only=True, frozen=True, slots=True) +class GetTeamsCommand: + """Input for the use case 'Get Teams'.""" + + offset: int | None = None + limit: int | None = None + + +class GetTeams: + """Implement the use case 'Get Teams'.""" + + def __init__( + self, + team_repo: TeamRepository, + presenter: AsyncPresenter[IterableResult[TeamEntity]], + ): + """Initialize the use case.""" + self._team_repo = team_repo + self._presenter = presenter + + async def execute(self, command: GetTeamsCommand) -> None: + """Execute the use case.""" + query = self._team_repo.create_query() + await self._presenter.present( + IterableResult( + count=await query.count(), + limit=command.limit, + offset=command.offset, + iterator=self._team_repo.get_all(query, command.offset, command.limit), + ) + ) diff --git a/backend/src/kwai/modules/teams/repositories/__init__.py b/backend/src/kwai/modules/teams/repositories/__init__.py new file mode 100644 index 000000000..96987a8f8 --- /dev/null +++ b/backend/src/kwai/modules/teams/repositories/__init__.py @@ -0,0 +1 @@ +"""Package for the repositories of the teams module.""" diff --git a/backend/src/kwai/modules/teams/repositories/_tables.py b/backend/src/kwai/modules/teams/repositories/_tables.py new file mode 100644 index 000000000..20b67a2f5 --- /dev/null +++ b/backend/src/kwai/modules/teams/repositories/_tables.py @@ -0,0 +1,148 @@ +from dataclasses import dataclass +from datetime import date, datetime +from typing import Self + +from kwai.core.db.table_row import TableRow +from kwai.core.domain.value_objects.timestamp import Timestamp +from kwai.core.domain.value_objects.traceable_time import TraceableTime +from kwai.core.domain.value_objects.unique_id import UniqueId +from kwai.modules.club.domain.country import CountryEntity, CountryIdentifier +from kwai.modules.teams.domain.team import TeamEntity, TeamIdentifier +from kwai.modules.teams.domain.team_member import MemberEntity, TeamMember + + +@dataclass(kw_only=True, frozen=True, slots=True) +class TeamRow(TableRow): + """Represents a row of the teams table.""" + + __table_name__ = "teams" + + id: int + name: str + season_id: int | None + team_category_id: int | None + active: int + remark: str | None + created_at: datetime + updated_at: datetime | None + + def create_entity(self, team_members: dict[UniqueId, TeamMember]) -> TeamEntity: + return TeamEntity( + id_=TeamIdentifier(self.id), + name=self.name, + active=self.active == 1, + remark=self.remark or "", + members=team_members, + traceable_time=TraceableTime( + created_at=Timestamp.create_utc(self.created_at), + updated_at=Timestamp.create_utc(self.updated_at), + ), + ) + + @classmethod + def persist(cls, team: TeamEntity) -> Self: + return cls( + id=team.id.value, + name=team.name, + season_id=None, + team_category_id=None, + active=1 if team.is_active else 0, + remark=team.remark, + created_at=team.traceable_time.created_at.timestamp, # type: ignore[arg-type] + updated_at=team.traceable_time.updated_at.timestamp, + ) + + +@dataclass(kw_only=True, frozen=True, slots=True) +class MemberRow(TableRow): + """Represents a row of the members table used for a team member.""" + + __table_name__ = "judo_members" + + id: int | None + uuid: str | None + license: str | None + license_end_date: date | None + person_id: int | None + active: int | None + + +@dataclass(kw_only=True, frozen=True, slots=True) +class MemberPersonRow(TableRow): + """Represents a row of the persons table used for a team member.""" + + __table_name__ = "persons" + + id: int | None + firstname: str | None + lastname: str | None + gender: int | None + birthdate: date | None + nationality_id: int | None + + +@dataclass(kw_only=True, frozen=True, slots=True) +class TeamMemberRow(TableRow): + """Represents a row of the team members table.""" + + __table_name__ = "team_members" + + team_id: int | None + member_id: int | None + active: int | None + created_at: datetime | None + updated_at: datetime | None + + def create_team_member(self, member: MemberEntity): + return TeamMember( + active=True if self.active == 1 else False, + member=member, + traceable_time=TraceableTime( + created_at=Timestamp.create_utc(self.created_at), + updated_at=Timestamp.create_utc(self.updated_at), + ), + ) + + @classmethod + def persist(cls, team: TeamEntity, team_member: TeamMember) -> Self: + """Persist a team member to the table row.""" + return cls( + team_id=team.id.value, + member_id=team_member.member.id.value, + active=1 if team_member.active else 0, + created_at=team_member.traceable_time.created_at.timestamp, # type: ignore[arg-type] + updated_at=team_member.traceable_time.updated_at.timestamp, + ) + + +@dataclass(kw_only=True, frozen=True, slots=True) +class CountryRow(TableRow): + """Represent a row of the countries table. + + Attributes: + id: The id of the country. + iso_2: The ISO 2 code of the country. + iso_3: The ISO 3 code of the country. + """ + + __table_name__ = "countries" + + id: int | None = None + iso_2: str | None + iso_3: str | None + name: str | None + created_at: datetime | None + updated_at: datetime | None + + def create_country(self) -> CountryEntity: + """Create a Country value object from the row. + + Returns: + A country value object. + """ + return CountryEntity( + id_=CountryIdentifier(self.id), + iso_2=self.iso_2, + iso_3=self.iso_3, + name=self.name, + ) diff --git a/backend/src/kwai/modules/teams/repositories/member_db_repository.py b/backend/src/kwai/modules/teams/repositories/member_db_repository.py new file mode 100644 index 000000000..5e8e0da64 --- /dev/null +++ b/backend/src/kwai/modules/teams/repositories/member_db_repository.py @@ -0,0 +1,138 @@ +"""Module for defining a team member repository for a database.""" + +from dataclasses import dataclass +from typing import AsyncGenerator, Self + +from sql_smith.functions import express, on + +from kwai.core.db.database import Database +from kwai.core.db.database_query import DatabaseQuery +from kwai.core.db.table_row import JoinedTableRow +from kwai.core.domain.value_objects.date import Date +from kwai.core.domain.value_objects.name import Name +from kwai.core.domain.value_objects.unique_id import UniqueId +from kwai.modules.club.domain.value_objects import Birthdate, Gender, License +from kwai.modules.teams.domain.team import TeamIdentifier +from kwai.modules.teams.domain.team_member import MemberEntity, MemberIdentifier +from kwai.modules.teams.repositories._tables import ( + CountryRow, + MemberPersonRow, + MemberRow, + TeamMemberRow, +) +from kwai.modules.teams.repositories.member_repository import ( + MemberNotFoundException, + MemberQuery, + MemberRepository, +) + + +@dataclass(kw_only=True, frozen=True, slots=True) +class MemberQueryRow(JoinedTableRow): + """A data transfer object for the member query.""" + + member: MemberRow + person: MemberPersonRow + country: CountryRow + + def create_entity(self) -> MemberEntity: + """Create a team member entity from a row.""" + return MemberEntity( + id_=MemberIdentifier(self.member.id), + uuid=UniqueId.create_from_string(self.member.uuid), + name=Name(first_name=self.person.firstname, last_name=self.person.lastname), + license=License( + number=self.member.license, + end_date=Date.create_from_date(self.member.license_end_date), + ), + birthdate=Birthdate(Date.create_from_date(self.person.birthdate)), + gender=Gender(self.person.gender), + nationality=self.country.create_country(), + active_in_club=self.member.active == 1, + ) + + +class MemberDbQuery(MemberQuery, DatabaseQuery): + """A team member query for a database.""" + + def __init__(self, database: Database): + super().__init__(database) + + def init(self): + self._query.from_(MemberRow.__table_name__).inner_join( + MemberPersonRow.__table_name__, + on(MemberPersonRow.column("id"), MemberRow.column("person_id")), + ).inner_join( + CountryRow.__table_name__, + on(CountryRow.column("id"), MemberPersonRow.column("nationality_id")), + ) + + @property + def columns(self): + return MemberQueryRow.get_aliases() + + @property + def count_column(self): + return MemberRow.column("id") + + def filter_by_id(self, id_: MemberIdentifier) -> Self: + self._query.and_where(MemberRow.field("id").eq(id_.value)) + return self + + def filter_by_birthdate( + self, start_date: Date, end_date: Date | None = None + ) -> Self: + if end_date is None: + self._query.and_where(MemberPersonRow.field("birthdate").gte(start_date)) + else: + self._query.and_where( + MemberPersonRow.field("birthdate").between(start_date, end_date) + ) + return self + + def filter_by_uuid(self, uuid: UniqueId) -> Self: + self._query.and_where(MemberRow.field("uuid").eq(str(uuid))) + return self + + def filter_by_team(self, team_id: TeamIdentifier, in_team: bool = True) -> Self: + inner_select = ( + self._database.create_query_factory() + .select() + .columns(TeamMemberRow.column("member_id")) + .from_(TeamMemberRow.__table_name__) + .where(TeamMemberRow.field("team_id").eq(team_id.value)) + ) + if in_team: + condition = MemberRow.field("id").in_(express("{}", inner_select)) + else: + condition = MemberRow.field("id").not_in(express("{}", inner_select)) + self._query.and_where(condition) + return self + + +class MemberDbRepository(MemberRepository): + """A member repository for a database.""" + + def __init__(self, database: Database): + self._database = database + + def create_query(self) -> MemberQuery: + return MemberDbQuery(self._database) + + async def get(self, query: MemberQuery | None = None) -> MemberEntity: + team_member_iterator = self.get_all(query) + try: + return await anext(team_member_iterator) + except StopAsyncIteration: + raise MemberNotFoundException("Member not found") from None + + async def get_all( + self, + query: MemberQuery | None = None, + limit: int | None = None, + offset: int | None = None, + ) -> AsyncGenerator[MemberEntity, None]: + query = query or self.create_query() + + async for row in query.fetch(limit, offset): + yield MemberQueryRow.map(row).create_entity() diff --git a/backend/src/kwai/modules/teams/repositories/member_repository.py b/backend/src/kwai/modules/teams/repositories/member_repository.py new file mode 100644 index 000000000..13bb84b19 --- /dev/null +++ b/backend/src/kwai/modules/teams/repositories/member_repository.py @@ -0,0 +1,87 @@ +"""Module for defining the member repository interface.""" + +from abc import ABC, abstractmethod +from typing import AsyncGenerator, Self + +from kwai.core.domain.repository.query import Query +from kwai.core.domain.value_objects.date import Date +from kwai.core.domain.value_objects.unique_id import UniqueId +from kwai.modules.teams.domain.team import TeamIdentifier +from kwai.modules.teams.domain.team_member import MemberEntity, MemberIdentifier + + +class MemberNotFoundException(Exception): + """Raised when a member does not exist.""" + + +class MemberQuery(Query, ABC): + """An interface for a member query.""" + + @abstractmethod + def filter_by_id(self, id_: MemberIdentifier) -> Self: + """Find a team member by its id.""" + raise NotImplementedError + + @abstractmethod + def filter_by_uuid(self, uuid: UniqueId) -> Self: + """Find a team member by its uuid.""" + raise NotImplementedError + + @abstractmethod + def filter_by_birthdate( + self, start_date: Date, end_date: Date | None = None + ) -> Self: + """Find team members by their birthdate.""" + raise NotImplementedError + + @abstractmethod + def filter_by_team(self, team_id: TeamIdentifier, in_team: bool = True) -> Self: + """Find members that are (not) part of the team. + + To get only the members that are not part of the team, set in_team to False. + + Args: + team_id: The id of the team + in_team: Whether the member should be part of the team + """ + raise NotImplementedError + + +class MemberRepository(ABC): + """An interface for a member repository.""" + + @abstractmethod + def create_query(self) -> MemberQuery: + """Create a query for querying team members.""" + raise NotImplementedError + + @abstractmethod + async def get(self, query: MemberQuery | None = None) -> MemberEntity: + """Return the first returned element of the given query. + + Args: + query: The query to use for getting the first member. + + Raises: + MemberNotFoundException: If the member is not found. + """ + raise NotImplementedError + + @abstractmethod + def get_all( + self, + query: MemberQuery | None = None, + limit: int | None = None, + offset: int | None = None, + ) -> AsyncGenerator[MemberEntity, None]: + """Return all members of the given query. + + Args: + query: The query to use for getting the members. + limit: The maximum number of members to return. + offset: The offset to use for fetching members. + + Yields: + A team member entity. + """ + raise NotImplementedError diff --git a/backend/src/kwai/modules/teams/repositories/team_db_repository.py b/backend/src/kwai/modules/teams/repositories/team_db_repository.py new file mode 100644 index 000000000..7ef0ac494 --- /dev/null +++ b/backend/src/kwai/modules/teams/repositories/team_db_repository.py @@ -0,0 +1,179 @@ +"""Module that implements a team repository for a database.""" + +from dataclasses import dataclass +from typing import Any, AsyncGenerator, Self + +from sql_smith.functions import field, on + +from kwai.core.db.database import Database +from kwai.core.db.database_query import DatabaseQuery +from kwai.core.db.table_row import JoinedTableRow +from kwai.core.domain.entity import Entity +from kwai.core.domain.value_objects.date import Date +from kwai.core.domain.value_objects.name import Name +from kwai.core.domain.value_objects.unique_id import UniqueId +from kwai.core.functions import async_groupby +from kwai.modules.club.domain.value_objects import Birthdate, Gender, License +from kwai.modules.teams.domain.team import TeamEntity, TeamIdentifier +from kwai.modules.teams.domain.team_member import ( + MemberEntity, + MemberIdentifier, + TeamMember, +) +from kwai.modules.teams.repositories._tables import ( + CountryRow, + MemberPersonRow, + MemberRow, + TeamMemberRow, + TeamRow, +) +from kwai.modules.teams.repositories.team_repository import ( + TeamNotFoundException, + TeamQuery, + TeamRepository, +) + + +@dataclass(kw_only=True, frozen=True, slots=True) +class MemberPersonCountryMixin: + """Dataclass for a member related row.""" + + member: MemberRow + member_person: MemberPersonRow + country: CountryRow + + def create_member_entity(self) -> MemberEntity: + """Create a member entity from a row.""" + return MemberEntity( + id_=MemberIdentifier(self.member.id), + name=Name( + first_name=self.member_person.firstname, + last_name=self.member_person.lastname, + ), + license=License( + number=self.member.license, + end_date=Date.create_from_date(self.member.license_end_date), + ), + birthdate=Birthdate( + date=Date.create_from_date(self.member_person.birthdate) + ), + nationality=self.country.create_country(), + gender=Gender(self.member_person.gender), + uuid=UniqueId.create_from_string(self.member.uuid), + active_in_club=self.member.active == 1, + ) + + +@dataclass(kw_only=True, frozen=True, slots=True) +class TeamQueryRow(MemberPersonCountryMixin, JoinedTableRow): + """A data transfer object for the team query.""" + + team: TeamRow + team_member: TeamMemberRow + + @classmethod + def create_entity(cls, rows: list[dict[str, Any]]) -> TeamEntity: + """Create a team entity from a group of rows.""" + team_query_row = cls.map(rows[0]) + team_members = {} + for row in rows: + mapped_row = cls.map(row) + if mapped_row.member.id is None: + continue + + member = mapped_row.create_member_entity() + team_members[member.uuid] = mapped_row.team_member.create_team_member( + member + ) + return team_query_row.team.create_entity(team_members) + + +class TeamDbQuery(TeamQuery, DatabaseQuery): + """A team query for a database.""" + + def __init__(self, database: Database): + super().__init__(database) + + def init(self): + self._query.from_(TeamRow.__table_name__).left_join( + TeamMemberRow.__table_name__, + on(TeamRow.column("id"), TeamMemberRow.column("team_id")), + ).left_join( + MemberRow.__table_name__, + on(MemberRow.column("id"), TeamMemberRow.column("member_id")), + ).left_join( + MemberPersonRow.__table_name__, + on(MemberPersonRow.column("id"), MemberRow.column("person_id")), + ).left_join( + CountryRow.__table_name__, + on(CountryRow.column("id"), MemberPersonRow.column("nationality_id")), + ) + + @property + def columns(self): + return TeamQueryRow.get_aliases() + + @property + def count_column(self) -> str: + return TeamRow.column("id") + + def filter_by_id(self, id_: TeamIdentifier) -> Self: + self._query.and_where(TeamRow.field("id").eq(id_.value)) + return self + + +class TeamDbRepository(TeamRepository): + """A team repository for a database.""" + + def create_query(self) -> TeamQuery: + return TeamDbQuery(self._database) + + async def get(self, query: TeamQuery | None = None) -> TeamEntity: + team_iterator = self.get_all(query) + try: + return await anext(team_iterator) + except StopAsyncIteration: + raise TeamNotFoundException("Team not found") from None + + async def get_all( + self, + query: TeamQuery | None = None, + limit: int | None = None, + offset: int | None = None, + ) -> AsyncGenerator[TeamEntity, None]: + if query is None: + query = self.create_query() + + group_by_column = "team_id" + row_iterator = query.fetch(limit=limit, offset=offset) + async for _, group in async_groupby( + row_iterator, key=lambda row: row[group_by_column] + ): + yield TeamQueryRow.create_entity(group) + + def __init__(self, database: Database): + self._database = database + + async def create(self, team: TeamEntity) -> TeamEntity: + new_team_id = await self._database.insert( + TeamRow.__table_name__, TeamRow.persist(team) + ) + return Entity.replace(team, id_=TeamIdentifier(new_team_id)) + + async def delete(self, team: TeamEntity) -> None: + delete_team_members_query = ( + self._database.create_query_factory() + .delete(TeamMemberRow.__table_name__) + .where(field("team_id").eq(team.id.value)) + ) + await self._database.execute(delete_team_members_query) + await self._database.delete(team.id.value, TeamRow.__table_name__) + + async def update(self, team: TeamEntity): + await self._database.update( + team.id.value, TeamRow.__table_name__, TeamRow.persist(team) + ) + + async def add_team_member(self, team: TeamEntity, member: TeamMember): + team_member_row = TeamMemberRow.persist(team, member) + await self._database.insert(TeamMemberRow.__table_name__, team_member_row) diff --git a/backend/src/kwai/modules/teams/repositories/team_member_db_query.py b/backend/src/kwai/modules/teams/repositories/team_member_db_query.py new file mode 100644 index 000000000..57e844dbe --- /dev/null +++ b/backend/src/kwai/modules/teams/repositories/team_member_db_query.py @@ -0,0 +1,112 @@ +"""Module that defines a database query for team members.""" + +from collections import defaultdict +from dataclasses import dataclass +from typing import Self + +from sql_smith.functions import on + +from kwai.core.db.database_query import DatabaseQuery +from kwai.core.db.table_row import JoinedTableRow +from kwai.core.domain.value_objects.date import Date +from kwai.core.domain.value_objects.name import Name +from kwai.core.domain.value_objects.timestamp import Timestamp +from kwai.core.domain.value_objects.traceable_time import TraceableTime +from kwai.core.domain.value_objects.unique_id import UniqueId +from kwai.modules.club.domain.value_objects import Birthdate, Gender, License +from kwai.modules.teams.domain.team import TeamIdentifier +from kwai.modules.teams.domain.team_member import ( + MemberEntity, + MemberIdentifier, + TeamMember, +) +from kwai.modules.teams.repositories._tables import ( + CountryRow, + MemberPersonRow, + MemberRow, + TeamMemberRow, +) + + +@dataclass(frozen=True, kw_only=True, slots=True) +class TeamMemberQueryRow(JoinedTableRow): + """A data transfer object for the team member query.""" + + team_member: TeamMemberRow + member: MemberRow + person: MemberPersonRow + country: CountryRow + + def create_team_member(self) -> TeamMember: + """Create a team member from a row.""" + return TeamMember( + active=self.team_member.active == 1, + member=MemberEntity( + id_=MemberIdentifier(self.member.id), + uuid=UniqueId.create_from_string(self.member.uuid), + name=Name( + first_name=self.person.firstname, last_name=self.person.lastname + ), + license=License( + number=self.member.license, + end_date=Date.create_from_date(self.member.license_end_date), + ), + birthdate=Birthdate(Date.create_from_date(self.person.birthdate)), + gender=Gender(self.person.gender), + nationality=self.country.create_country(), + active_in_club=self.member.active == 1, + ), + traceable_time=TraceableTime( + created_at=Timestamp(self.team_member.created_at), + updated_at=Timestamp(self.team_member.updated_at), + ), + ) + + +class TeamMemberDbQuery(DatabaseQuery): + """A database query for getting team members.""" + + def init(self): + self._query.from_(TeamMemberRow.__table_name__).left_join( + MemberRow.__table_name__, + on(TeamMemberRow.column("member_id"), MemberRow.column("id")), + ).join( + MemberPersonRow.__table_name__, + on(MemberRow.column("person_id"), MemberPersonRow.column("id")), + ).inner_join( + CountryRow.__table_name__, + on(CountryRow.column("id"), MemberPersonRow.column("nationality_id")), + ) + + @property + def columns(self): + return TeamMemberQueryRow.get_aliases() + + def filter_by_teams(self, *ids: TeamIdentifier) -> Self: + """Filter by teams. + + Only the rows that belong to the teams with the given ids, will be returned. + """ + unpacked_ids = tuple(i.value for i in ids) + self._query.and_where(TeamMemberRow.field("team_id").in_(*unpacked_ids)) + return self + + async def fetch_team_members(self) -> dict[TeamIdentifier, list[TeamMember]]: + """Fetch team members. + + A specialized fetch method that already transforms the rows into TeamMember + objects. + + Returns: + A dictionary that contains the list of team members for each team. + The key is the identifier of the team. + """ + result: dict[TeamIdentifier, list[TeamMember]] = defaultdict(list) + + async for row in self.fetch(): + team_member_row = TeamMemberQueryRow.map(row) + result[TeamIdentifier(team_member_row.team_member.team_id)].append( + team_member_row.create_team_member() + ) + + return result diff --git a/backend/src/kwai/modules/teams/repositories/team_repository.py b/backend/src/kwai/modules/teams/repositories/team_repository.py new file mode 100644 index 000000000..ddd72e865 --- /dev/null +++ b/backend/src/kwai/modules/teams/repositories/team_repository.py @@ -0,0 +1,78 @@ +"""Module that defines an interface for a team repository.""" + +from abc import ABC, abstractmethod +from typing import AsyncGenerator, Self + +from kwai.core.domain.repository.query import Query +from kwai.modules.teams.domain.team import TeamEntity, TeamIdentifier +from kwai.modules.teams.domain.team_member import TeamMember + + +class TeamNotFoundException(Exception): + """Raised when a team cannot be found.""" + + +class TeamQuery(Query, ABC): + """An interface for a team query.""" + + @abstractmethod + def filter_by_id(self, id_: TeamIdentifier) -> Self: + """Find a team by its id.""" + raise NotImplementedError + + +class TeamRepository(ABC): + """An interface for a team repository.""" + + @abstractmethod + def create_query(self) -> TeamQuery: + """Create a team query.""" + raise NotImplementedError + + @abstractmethod + async def get(self, query: TeamQuery | None = None) -> TeamEntity: + """Return the first returned element of the given query. + + Args: + query: The query to use for getting the first team. + + Raises: + TeamNotFoundException: If the team cannot be found. + """ + raise NotImplementedError + + @abstractmethod + def get_all( + self, + query: TeamQuery | None = None, + limit: int | None = None, + offset: int | None = None, + ) -> AsyncGenerator[TeamEntity, None]: + """Return all teams of the given query. + + Args: + query: The query to use for getting the teams. + limit: The maximum number of teams to return. + offset: The offset to use for fetching teams. + + Yields: + A team entity. + + """ + raise NotImplementedError + + @abstractmethod + async def create(self, team: TeamEntity) -> TeamEntity: + """Save a new team.""" + + @abstractmethod + async def delete(self, team: TeamEntity) -> None: + """Delete a team.""" + + @abstractmethod + async def update(self, team: TeamEntity) -> None: + """Update a team.""" + + @abstractmethod + async def add_team_member(self, team: TeamEntity, member: TeamMember): + """Add a member to a team.""" diff --git a/backend/src/kwai/modules/teams/update_team.py b/backend/src/kwai/modules/teams/update_team.py new file mode 100644 index 000000000..e52fb1df5 --- /dev/null +++ b/backend/src/kwai/modules/teams/update_team.py @@ -0,0 +1,53 @@ +"""Module that defines the Update Team use case.""" + +from dataclasses import dataclass + +from kwai.core.domain.entity import Entity +from kwai.core.domain.presenter import Presenter +from kwai.modules.teams.domain.team import TeamEntity, TeamIdentifier +from kwai.modules.teams.repositories.team_repository import TeamRepository + + +@dataclass(frozen=True, kw_only=True, slots=True) +class UpdateTeamCommand: + """Input for the Update Team use case.""" + + id: int + name: str + active: bool + remark: str + + +class UpdateTeam: + """Use case for updating a team.""" + + def __init__(self, team_repo: TeamRepository, presenter: Presenter[TeamEntity]): + """Initialize the use case. + + Args: + team_repo: A repository for updating the team. + presenter: A presenter for a team entity. + """ + self._team_repo = team_repo + self._presenter = presenter + + async def execute(self, command: UpdateTeamCommand) -> None: + """Execute the use case. + + Raises: + TeamNotFoundException: raise when the team does not exist. + """ + team = await self._team_repo.get( + self._team_repo.create_query().filter_by_id(TeamIdentifier(command.id)) + ) + + team = Entity.replace( + team, + name=command.name, + active=command.active, + remark=command.remark, + traceable_time=team.traceable_time.mark_for_update(), + ) + await self._team_repo.update(team) + + self._presenter.present(team) diff --git a/backend/src/kwai/modules/training/coaches/_tables.py b/backend/src/kwai/modules/training/coaches/_tables.py new file mode 100644 index 000000000..5cc439e3a --- /dev/null +++ b/backend/src/kwai/modules/training/coaches/_tables.py @@ -0,0 +1,36 @@ +"""Module that defines all dataclasses for the tables containing coaches.""" + +from dataclasses import dataclass + +from kwai.core.db.table_row import TableRow + + +@dataclass(kw_only=True, frozen=True, slots=True) +class MemberRow(TableRow): + """Represent a row of the members table.""" + + __table_name__ = "judo_members" + + id: int + + +@dataclass(kw_only=True, frozen=True, slots=True) +class PersonRow(TableRow): + """Represent a row of the persons table.""" + + __table_name__ = "persons" + + id: int + lastname: str + firstname: str + + +@dataclass(kw_only=True, frozen=True, slots=True) +class CoachRow(TableRow): + """Represent a row of the coaches table.""" + + __table_name__ = "coaches" + + id: int + member_id: int + active: int diff --git a/backend/src/kwai/modules/training/coaches/coach_db_query.py b/backend/src/kwai/modules/training/coaches/coach_db_query.py index 3f4081809..8a3fa4bc3 100644 --- a/backend/src/kwai/modules/training/coaches/coach_db_query.py +++ b/backend/src/kwai/modules/training/coaches/coach_db_query.py @@ -1,10 +1,36 @@ """Module that defines a database query for coaches.""" + +from dataclasses import dataclass + from sql_smith.functions import on from kwai.core.db.database_query import DatabaseQuery -from kwai.modules.training.coaches.coach import CoachIdentifier +from kwai.core.db.table_row import JoinedTableRow +from kwai.core.domain.value_objects.name import Name +from kwai.modules.training.coaches._tables import ( + CoachRow, + MemberRow, + PersonRow, +) +from kwai.modules.training.coaches.coach import CoachEntity, CoachIdentifier from kwai.modules.training.coaches.coach_query import CoachQuery -from kwai.modules.training.coaches.coach_tables import CoachesTable, PersonsTable + + +@dataclass(kw_only=True, frozen=True, slots=True) +class CoachQueryRow(JoinedTableRow): + """A data transfer object for the coach query.""" + + member: MemberRow + person: PersonRow + coach: CoachRow + + def create_entity(self) -> CoachEntity: + """Create a coach entity from a row.""" + return CoachEntity( + id_=CoachIdentifier(self.coach.id), + name=Name(first_name=self.person.firstname, last_name=self.person.lastname), + active=self.coach.active == 1, + ) class CoachDbQuery(DatabaseQuery, CoachQuery): @@ -12,29 +38,30 @@ class CoachDbQuery(DatabaseQuery, CoachQuery): @property def count_column(self) -> str: - return CoachesTable.column("id") + return CoachRow.column("id") def init(self): - self._query.from_(CoachesTable.table_name).columns( - *(CoachesTable.aliases() + PersonsTable.aliases()) - ).join( - PersonsTable.table_name, - on(CoachesTable.column("person_id"), PersonsTable.column("id")), + self._query.from_(CoachRow.__table_name__).join( + MemberRow.__table_name__, + on(MemberRow.column("id"), CoachRow.column("member_id")), + ).inner_join( + PersonRow.__table_name__, + on(MemberRow.column("person_id"), PersonRow.column("id")), ) @property def columns(self): - return CoachesTable.aliases() + PersonsTable.aliases() + return CoachQueryRow.get_aliases() def filter_by_ids(self, *ids: CoachIdentifier) -> "CoachQuery": unpacked_ids = tuple(i.value for i in ids) - self._query.and_where(CoachesTable.field("id").in_(*unpacked_ids)) + self._query.and_where(CoachRow.field("id").in_(*unpacked_ids)) return self def filter_by_id(self, id_: CoachIdentifier) -> "CoachQuery": - self._query.and_where(CoachesTable.field("id").eq(id_.value)) + self._query.and_where(CoachRow.field("id").eq(id_.value)) return self def filter_by_active(self) -> "CoachQuery": - self._query.and_where(CoachesTable.field("active").eq(1)) + self._query.and_where(CoachRow.field("active").eq(1)) return self diff --git a/backend/src/kwai/modules/training/coaches/coach_db_repository.py b/backend/src/kwai/modules/training/coaches/coach_db_repository.py index 723e54d5e..22440e270 100644 --- a/backend/src/kwai/modules/training/coaches/coach_db_repository.py +++ b/backend/src/kwai/modules/training/coaches/coach_db_repository.py @@ -1,20 +1,19 @@ """Module that defines a coach repository for a database.""" + from typing import AsyncIterator from kwai.core.db.database import Database +from kwai.modules.training.coaches._tables import ( + CoachRow, + PersonRow, +) from kwai.modules.training.coaches.coach import CoachEntity, CoachIdentifier -from kwai.modules.training.coaches.coach_db_query import CoachDbQuery +from kwai.modules.training.coaches.coach_db_query import CoachDbQuery, CoachQueryRow from kwai.modules.training.coaches.coach_query import CoachQuery from kwai.modules.training.coaches.coach_repository import ( CoachNotFoundException, CoachRepository, ) -from kwai.modules.training.coaches.coach_tables import ( - CoachesTable, - CoachRow, - PersonRow, - PersonsTable, -) def _create_entity(coach_row: CoachRow, person_row: PersonRow) -> CoachEntity: @@ -43,17 +42,17 @@ async def get_by_id(self, id: CoachIdentifier) -> CoachEntity: if not row: raise CoachNotFoundException(f"Coach with id {id} not found.") - return _create_entity(CoachesTable(row), PersonsTable(row)) + return CoachQueryRow.map(row).create_entity() async def get_by_ids(self, *ids: CoachIdentifier) -> AsyncIterator[CoachEntity]: query = self.create_query().filter_by_ids(*ids) async for row in query.fetch(): - yield _create_entity(CoachesTable(row), PersonsTable(row)) + yield CoachQueryRow.map(row).create_entity() async def get_all( self, query: CoachQuery | None = None ) -> AsyncIterator[CoachEntity]: query = query or self.create_query() async for row in query.fetch(): - yield _create_entity(CoachesTable(row), PersonsTable(row)) + yield CoachQueryRow.map(row).create_entity() diff --git a/backend/src/kwai/modules/training/coaches/coach_tables.py b/backend/src/kwai/modules/training/coaches/coach_tables.py deleted file mode 100644 index 10c719c8e..000000000 --- a/backend/src/kwai/modules/training/coaches/coach_tables.py +++ /dev/null @@ -1,38 +0,0 @@ -"""Module that defines all dataclasses for the tables containing coaches.""" -from dataclasses import dataclass - -from kwai.core.db.table import Table -from kwai.core.domain.value_objects.name import Name -from kwai.modules.training.coaches.coach import CoachEntity, CoachIdentifier - - -@dataclass(kw_only=True, frozen=True, slots=True) -class PersonRow: - """Represent a row of the persons table.""" - - id: int - lastname: str - firstname: str - - -PersonsTable = Table("persons", PersonRow) - - -@dataclass(kw_only=True, frozen=True, slots=True) -class CoachRow: - """Represent a row of the coaches table.""" - - id: int - person_id: int - active: int - - def create_entity(self, person_row: PersonRow) -> CoachEntity: - """Create a coach entity from this row.""" - return CoachEntity( - id_=CoachIdentifier(self.id), - name=Name(first_name=person_row.firstname, last_name=person_row.lastname), - active=self.active == 1, - ) - - -CoachesTable = Table("coaches", CoachRow) diff --git a/backend/src/kwai/modules/training/create_training_definition.py b/backend/src/kwai/modules/training/create_training_definition.py index 01e151fde..6511014f0 100644 --- a/backend/src/kwai/modules/training/create_training_definition.py +++ b/backend/src/kwai/modules/training/create_training_definition.py @@ -43,7 +43,7 @@ async def execute( command: The input for this use case. """ if command.team_id is not None: - team = self._team_repo.get_by_id(TeamIdentifier(command.team_id)) + team = await self._team_repo.get_by_id(TeamIdentifier(command.team_id)) else: team = None diff --git a/backend/src/kwai/modules/training/delete_training_definition.py b/backend/src/kwai/modules/training/delete_training_definition.py index 20940dc55..700edf190 100644 --- a/backend/src/kwai/modules/training/delete_training_definition.py +++ b/backend/src/kwai/modules/training/delete_training_definition.py @@ -1,4 +1,5 @@ """Module for the use case "Delete Training Definition".""" + from dataclasses import dataclass from kwai.modules.training.trainings.training_definition import ( @@ -41,8 +42,8 @@ async def execute(self, command: DeleteTrainingDefinitionCommand): """Execute the use case. Raises: - TrainingDefinitionNotFoundException when the training definition - does not exist. + TrainingDefinitionNotFoundException: when the training definition + does not exist. """ training_definition = await self._repo.get_by_id( TrainingDefinitionIdentifier(command.id) diff --git a/backend/src/kwai/modules/training/trainings/training_coach_db_query.py b/backend/src/kwai/modules/training/trainings/training_coach_db_query.py index 060ac84ed..6f43d7e14 100644 --- a/backend/src/kwai/modules/training/trainings/training_coach_db_query.py +++ b/backend/src/kwai/modules/training/trainings/training_coach_db_query.py @@ -1,39 +1,78 @@ """Module that defines a database query to get coaches of training(s).""" + from collections import defaultdict +from dataclasses import dataclass from sql_smith.functions import on from kwai.core.db.database_query import DatabaseQuery -from kwai.core.db.rows import OwnersTable -from kwai.modules.training.coaches.coach_tables import CoachesTable, PersonsTable +from kwai.core.db.rows import OwnersTable, OwnerTableRow +from kwai.core.db.table_row import JoinedTableRow +from kwai.core.domain.value_objects.name import Name +from kwai.modules.training.coaches._tables import ( # noqa + CoachRow, + MemberRow, + PersonRow, +) +from kwai.modules.training.coaches.coach import CoachEntity, CoachIdentifier from kwai.modules.training.trainings.training import TrainingIdentifier -from kwai.modules.training.trainings.training_tables import TrainingCoachesTable +from kwai.modules.training.trainings.training_tables import ( + TrainingCoachRow, +) from kwai.modules.training.trainings.value_objects import TrainingCoach +@dataclass(kw_only=True, frozen=True, slots=True) +class TrainingCoachQueryRow(JoinedTableRow): + """A data transfer object for the training coach query.""" + + training_coach: TrainingCoachRow + member: MemberRow + person: PersonRow + coach: CoachRow + owner: OwnerTableRow + + def create_coach(self) -> TrainingCoach: + """Create a training coach from a row.""" + return TrainingCoach( + coach=CoachEntity( + id_=CoachIdentifier(self.coach.id), + name=Name( + first_name=self.person.firstname, last_name=self.person.lastname + ), + active=self.coach.active == 1, + ), + owner=self.owner.create_owner(), + present=self.training_coach.present == 1, + type=self.training_coach.coach_type, + payed=self.training_coach.payed == 1, + remark=( + "" if self.training_coach.remark is None else self.training_coach.remark + ), + ) + + class TrainingCoachDbQuery(DatabaseQuery): """A database query for getting coaches of training(s).""" def init(self): - self._query.from_(TrainingCoachesTable.table_name).left_join( - CoachesTable.table_name, - on(TrainingCoachesTable.column("coach_id"), CoachesTable.column("id")), + self._query.from_(TrainingCoachRow.__table_name__).left_join( + CoachRow.__table_name__, + on(TrainingCoachRow.column("coach_id"), CoachRow.column("id")), + ).join( + MemberRow.__table_name__, + on(CoachRow.column("member_id"), MemberRow.column("id")), ).join( - PersonsTable.table_name, - on(CoachesTable.column("person_id"), PersonsTable.column("id")), + PersonRow.__table_name__, + on(MemberRow.column("person_id"), PersonRow.column("id")), ).join( OwnersTable.table_name, - on(CoachesTable.column("user_id"), OwnersTable.column("id")), + on(CoachRow.column("user_id"), OwnerTableRow.column("id")), ) @property def columns(self): - return ( - TrainingCoachesTable.aliases() - + CoachesTable.aliases() - + PersonsTable.aliases() - + OwnersTable.aliases() - ) + return TrainingCoachQueryRow.get_aliases() def filter_by_trainings(self, *ids: TrainingIdentifier) -> "TrainingCoachDbQuery": """Filter by trainings. @@ -41,9 +80,7 @@ def filter_by_trainings(self, *ids: TrainingIdentifier) -> "TrainingCoachDbQuery Only the rows of the trainings with the given ids, will be returned. """ unpacked_ids = tuple(i.value for i in ids) - self._query.and_where( - TrainingCoachesTable.field("training_id").in_(*unpacked_ids) - ) + self._query.and_where(TrainingCoachRow.field("training_id").in_(*unpacked_ids)) return self async def fetch_coaches(self) -> dict[TrainingIdentifier, list[TrainingCoach]]: @@ -58,15 +95,9 @@ async def fetch_coaches(self) -> dict[TrainingIdentifier, list[TrainingCoach]]: """ result: dict[TrainingIdentifier, list[TrainingCoach]] = defaultdict(list) - async for record in self.fetch(): - training_coach = TrainingCoachesTable(record) - owner_row = OwnersTable(record).create_owner() - coach_row = CoachesTable(record) - person_row = PersonsTable(record) - result[TrainingIdentifier(training_coach.training_id)].append( - training_coach.create_coach( - coach_row.create_entity(person_row), - owner_row, - ) - ) + async for row in self.fetch(): + training_coach_row = TrainingCoachQueryRow.map(row) + result[ + TrainingIdentifier(training_coach_row.training_coach.training_id) + ].append(training_coach_row.create_coach()) return result diff --git a/backend/src/kwai/modules/training/trainings/training_db_query.py b/backend/src/kwai/modules/training/trainings/training_db_query.py index 4ca46f141..88c6b2303 100644 --- a/backend/src/kwai/modules/training/trainings/training_db_query.py +++ b/backend/src/kwai/modules/training/trainings/training_db_query.py @@ -1,6 +1,5 @@ """Module that implements a training query for a database.""" -from datetime import datetime from typing import AsyncIterator from sql_smith.functions import alias, criteria, express, func, group, literal, on @@ -8,6 +7,7 @@ from kwai.core.db.database import Database from kwai.core.db.database_query import DatabaseQuery from kwai.core.db.rows import OwnersTable +from kwai.core.domain.value_objects.timestamp import Timestamp from kwai.modules.training.coaches.coach import CoachEntity from kwai.modules.training.teams.team import TeamEntity from kwai.modules.training.teams.team_tables import TeamsTable @@ -15,7 +15,7 @@ from kwai.modules.training.trainings.training_definition import TrainingDefinitionEntity from kwai.modules.training.trainings.training_query import TrainingQuery from kwai.modules.training.trainings.training_tables import ( - TrainingCoachesTable, + TrainingCoachRow, TrainingContentsTable, TrainingDefinitionsTable, TrainingsTable, @@ -110,17 +110,19 @@ def filter_by_year_month( self._query.and_where(group(condition)) return self - def filter_by_dates(self, start: datetime, end: datetime) -> "TrainingQuery": - self._query.and_where(TrainingsTable.field("start_date").between(start, end)) + def filter_by_dates(self, start: Timestamp, end: Timestamp) -> "TrainingQuery": + self._query.and_where( + TrainingsTable.field("start_date").between(str(start), str(end)) + ) return self def filter_by_coach(self, coach: CoachEntity) -> "TrainingQuery": inner_select = ( self._database.create_query_factory() .select() - .columns(TrainingCoachesTable.column("training_id")) - .from_(TrainingCoachesTable.table_name) - .where(TrainingCoachesTable.field("coach_id").eq(coach.id.value)) + .columns(TrainingCoachRow.column("training_id")) + .from_(TrainingCoachRow.__table_name__) + .where(TrainingCoachRow.field("coach_id").eq(coach.id.value)) ) condition = TrainingsTable.field("id").in_(express("{}", inner_select)) self._query.and_where(group(condition)) diff --git a/backend/src/kwai/modules/training/trainings/training_db_repository.py b/backend/src/kwai/modules/training/trainings/training_db_repository.py index 0c59082ca..289b4c6df 100644 --- a/backend/src/kwai/modules/training/trainings/training_db_repository.py +++ b/backend/src/kwai/modules/training/trainings/training_db_repository.py @@ -1,4 +1,5 @@ """Module for implementing a training repository for a database.""" + from typing import AsyncIterator from sql_smith.functions import alias, express, field @@ -18,7 +19,6 @@ TrainingRepository, ) from kwai.modules.training.trainings.training_tables import ( - TrainingCoachesTable, TrainingCoachRow, TrainingContentsTable, TrainingDefinitionsTable, @@ -117,17 +117,17 @@ async def get_all( training_query = TrainingCoachDbQuery(self._database).filter_by_trainings( *trainings.keys() ) - coaches: dict[ - TrainingIdentifier, list[TrainingCoach] - ] = await training_query.fetch_coaches() + coaches: dict[TrainingIdentifier, list[TrainingCoach]] = ( + await training_query.fetch_coaches() + ) # Get the teams of all trainings team_query = TrainingTeamDbQuery(self._database).filter_by_trainings( *trainings.keys() ) - teams: dict[ - TrainingIdentifier, list[TeamEntity] - ] = await team_query.fetch_teams() + teams: dict[TrainingIdentifier, list[TeamEntity]] = ( + await team_query.fetch_teams() + ) for training in trainings.values(): training_coaches = coaches.get(training.id, []) @@ -190,7 +190,7 @@ async def _insert_coaches(self, training: TrainingEntity): ] if training_coach_rows: await self._database.insert( - TrainingCoachesTable.table_name, *training_coach_rows + TrainingCoachRow.__table_name__, *training_coach_rows ) async def _insert_teams(self, training: TrainingEntity): @@ -207,7 +207,7 @@ async def _delete_coaches(self, training: TrainingEntity): """Delete coaches of the training.""" delete_coaches_query = ( self._database.create_query_factory() - .delete(TrainingCoachesTable.table_name) + .delete(TrainingCoachRow.__table_name__) .where(field("training_id").eq(training.id.value)) ) await self._database.execute(delete_coaches_query) @@ -258,10 +258,8 @@ async def reset_definition( delete_coaches = ( self._database.create_query_factory() - .delete(TrainingCoachesTable.table_name) - .and_where( - TrainingCoachesTable.field("training_id").in_(trainings_query) - ) + .delete(TrainingCoachRow.__table_name__) + .and_where(TrainingCoachRow.field("training_id").in_(trainings_query)) ) await self._database.execute(delete_coaches) diff --git a/backend/src/kwai/modules/training/trainings/training_query.py b/backend/src/kwai/modules/training/trainings/training_query.py index c092809e7..a12aab982 100644 --- a/backend/src/kwai/modules/training/trainings/training_query.py +++ b/backend/src/kwai/modules/training/trainings/training_query.py @@ -1,8 +1,9 @@ """Module that defines an interface for a training query.""" + from abc import ABC, abstractmethod -from datetime import datetime from kwai.core.domain.repository.query import Query +from kwai.core.domain.value_objects.timestamp import Timestamp from kwai.modules.training.coaches.coach import CoachEntity from kwai.modules.training.teams.team import TeamEntity from kwai.modules.training.trainings.training import TrainingIdentifier @@ -34,7 +35,7 @@ def filter_by_year_month( raise NotImplementedError @abstractmethod - def filter_by_dates(self, start: datetime, end: datetime) -> "TrainingQuery": + def filter_by_dates(self, start: Timestamp, end: Timestamp) -> "TrainingQuery": """Add filter to get only trainings between two dates. Args: diff --git a/backend/src/kwai/modules/training/trainings/training_tables.py b/backend/src/kwai/modules/training/trainings/training_tables.py index e8f5be37a..9dcfac9f2 100644 --- a/backend/src/kwai/modules/training/trainings/training_tables.py +++ b/backend/src/kwai/modules/training/trainings/training_tables.py @@ -5,6 +5,7 @@ from kwai.core.db.rows import TextRow from kwai.core.db.table import Table +from kwai.core.db.table_row import TableRow from kwai.core.domain.value_objects.owner import Owner from kwai.core.domain.value_objects.period import Period from kwai.core.domain.value_objects.text import LocaleText @@ -232,9 +233,11 @@ def persist( @dataclass(kw_only=True, frozen=True, slots=True) -class TrainingCoachRow: +class TrainingCoachRow(TableRow): """Represent a row of the training_coaches table.""" + __table_name__ = "training_coaches" + training_id: int coach_id: int coach_type: int @@ -272,9 +275,6 @@ def persist(cls, training, training_coach: TrainingCoach) -> "TrainingCoachRow": ) -TrainingCoachesTable = Table("training_coaches", TrainingCoachRow) - - @dataclass(kw_only=True, frozen=True, slots=True) class TrainingTeamRow: """Represent a row of the training_teams table.""" diff --git a/backend/src/kwai/modules/training/update_training_definition.py b/backend/src/kwai/modules/training/update_training_definition.py index c86b94c08..aeeea4734 100644 --- a/backend/src/kwai/modules/training/update_training_definition.py +++ b/backend/src/kwai/modules/training/update_training_definition.py @@ -54,7 +54,7 @@ async def execute( command: The input for this use case. Raises: - TrainingDefinitionNotFoundException when the training definition does not + TrainingDefinitionNotFoundException: when the training definition does not exist. """ if command.team_id is not None: diff --git a/backend/src/poetry.lock b/backend/src/poetry.lock deleted file mode 100644 index 5195c6ce5..000000000 --- a/backend/src/poetry.lock +++ /dev/null @@ -1,2985 +0,0 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. - -[[package]] -name = "aiohttp" -version = "3.9.3" -description = "Async http client/server framework (asyncio)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"}, - {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"}, - {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"}, - {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"}, - {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"}, - {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"}, - {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"}, - {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"}, - {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"}, - {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"}, - {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"}, - {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869"}, - {file = "aiohttp-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53"}, - {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6"}, - {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f"}, - {file = "aiohttp-3.9.3-cp312-cp312-win32.whl", hash = "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38"}, - {file = "aiohttp-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528"}, - {file = "aiohttp-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168"}, - {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321"}, - {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2"}, - {file = "aiohttp-3.9.3-cp38-cp38-win32.whl", hash = "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63"}, - {file = "aiohttp-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1"}, - {file = "aiohttp-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58"}, - {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a"}, - {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d"}, - {file = "aiohttp-3.9.3-cp39-cp39-win32.whl", hash = "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051"}, - {file = "aiohttp-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc"}, - {file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"}, -] - -[package.dependencies] -aiosignal = ">=1.1.2" -attrs = ">=17.3.0" -frozenlist = ">=1.1.1" -multidict = ">=4.5,<7.0" -yarl = ">=1.0,<2.0" - -[package.extras] -speedups = ["Brotli", "aiodns", "brotlicffi"] - -[[package]] -name = "aiosignal" -version = "1.3.1" -description = "aiosignal: a list of registered asynchronous callbacks" -optional = false -python-versions = ">=3.7" -files = [ - {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, - {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, -] - -[package.dependencies] -frozenlist = ">=1.1.0" - -[[package]] -name = "annotated-types" -version = "0.6.0" -description = "Reusable constraint types to use with typing.Annotated" -optional = false -python-versions = ">=3.8" -files = [ - {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, - {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, -] - -[[package]] -name = "anyio" -version = "4.3.0" -description = "High level compatibility layer for multiple asynchronous event loop implementations" -optional = false -python-versions = ">=3.8" -files = [ - {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, - {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, -] - -[package.dependencies] -idna = ">=2.8" -sniffio = ">=1.1" - -[package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.23)"] - -[[package]] -name = "async-lru" -version = "2.0.4" -description = "Simple LRU cache for asyncio" -optional = false -python-versions = ">=3.8" -files = [ - {file = "async-lru-2.0.4.tar.gz", hash = "sha256:b8a59a5df60805ff63220b2a0c5b5393da5521b113cd5465a44eb037d81a5627"}, - {file = "async_lru-2.0.4-py3-none-any.whl", hash = "sha256:ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224"}, -] - -[[package]] -name = "asyncmy" -version = "0.2.9" -description = "A fast asyncio MySQL driver" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "asyncmy-0.2.9-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:d077eaee9a126f36bbe95e0412baa89e93172dd46193ef7bf7650a686e458e50"}, - {file = "asyncmy-0.2.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83cf951a44294626df43c5a85cf328297c3bac63f25ede216f9706514dabb322"}, - {file = "asyncmy-0.2.9-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:8a1d63c1bb8e3a09c90767199954fd423c48084a1f6c0d956217bc2e48d37d6d"}, - {file = "asyncmy-0.2.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ecad6826086e47596c6aa65dcbe221305f3d9232f0d4de11b8562ee2c55464a"}, - {file = "asyncmy-0.2.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a664d58f9ebe4132f6cb3128206392be8ad71ad6fb09a5f4a990b04ec142024"}, - {file = "asyncmy-0.2.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f2bbd7b75e2d751216f48c3b1b5092b812d70c2cd0053f8d2f50ec3f76a525a8"}, - {file = "asyncmy-0.2.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:55e3bc41aa0d4ab410fc3a1d0c31b9cdb6688cd3b0cae6f2ee49c2e7f42968be"}, - {file = "asyncmy-0.2.9-cp310-cp310-win32.whl", hash = "sha256:ea44eefc965c62bcfebf34e9ef00f6e807edf51046046767c56914243e0737e4"}, - {file = "asyncmy-0.2.9-cp310-cp310-win_amd64.whl", hash = "sha256:2b4a2a7cf0bd5051931756e765fefef3c9f9561550e0dd8b1e79308d048b710a"}, - {file = "asyncmy-0.2.9-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:e2b77f03a17a8db338d74311e38ca6dbd4ff9aacb07d2af6b9e0cac9cf1c7b87"}, - {file = "asyncmy-0.2.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c19f27b7ff0e297f2981335a85599ffe1c9a8a35c97230203321d5d6e9e4cb30"}, - {file = "asyncmy-0.2.9-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:bf18aef65ac98f5130ca588c55a83a56e74ae416cf0fe2c0757a2b597c4269d0"}, - {file = "asyncmy-0.2.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef02186cc02cb767ee5d5cf9ab002d5c7910a1a9f4c16a666867a9325c9ec5e"}, - {file = "asyncmy-0.2.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:696da0f71db0fe11e62fa58cd5a27d7c9d9a90699d13d82640755d0061da0624"}, - {file = "asyncmy-0.2.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:84d20745bb187ced05bd4072ae8b0bff4b4622efa23b79935519edb717174584"}, - {file = "asyncmy-0.2.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ea242364523f6205c4426435272bd57cbf593c20d5e5551efb28d44cfbd595c2"}, - {file = "asyncmy-0.2.9-cp311-cp311-win32.whl", hash = "sha256:47609d34e6b49fc5ad5bd2a2a593ca120e143e2a4f4206f27a543c5c598a18ca"}, - {file = "asyncmy-0.2.9-cp311-cp311-win_amd64.whl", hash = "sha256:0d56df7342f7b5467a9d09a854f0e5602c8da09afdad8181ba40b0434d66d8a4"}, - {file = "asyncmy-0.2.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63c2a98f225560f9a52d5bd0d2e58517639e209e5d996e9ab7470e661b39394d"}, - {file = "asyncmy-0.2.9-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:20ae3acc326b4b104949cc5e3a728a927e671f671c6f26266ad4a44f57ea9a5b"}, - {file = "asyncmy-0.2.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8171a64888453423a17ae507cd97d256541ea880b314bba16376ab9deffef6e8"}, - {file = "asyncmy-0.2.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c966de493928f26218e0bfaa284cfa609540e52841c423d7babf9ca97c9ff820"}, - {file = "asyncmy-0.2.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4321c4cb4c691689aa26a56354e3fa723d89dc2cac82751e8671b2a4e6441778"}, - {file = "asyncmy-0.2.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cd7cde6759dbbfcc467c2af4ef3d75de0b756dde39a3d176383d8c6d9f8a34f3"}, - {file = "asyncmy-0.2.9-cp37-cp37m-win32.whl", hash = "sha256:7678d3641d5a19f20e7e19220c83405fe8616a3b437efbc494f34ad186cedcf0"}, - {file = "asyncmy-0.2.9-cp37-cp37m-win_amd64.whl", hash = "sha256:e8f48d09adf3426e7a59066eaae3c7c84c318ec56cc2f20732d652056c7a3f62"}, - {file = "asyncmy-0.2.9-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:4c4f1dc0acbaac8c3f046215031bbf3ca3d2cd7716244365325496e4f6222b78"}, - {file = "asyncmy-0.2.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:901aac048e5342acc62e1f68f6dec5aa3ed272cb2b138dca38d1c74fc414285d"}, - {file = "asyncmy-0.2.9-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:c2d4ad8817f99d9734912c2ff91c42e419031441f512b4aecd7e40a167908c1c"}, - {file = "asyncmy-0.2.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544d3736fd6682f0201a123e4f49335420b6abf6c245abe0487f5967021f1436"}, - {file = "asyncmy-0.2.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f0c606a55625146e189534cc39038540f7a8f2c680ea82845c1f4315a9ad2914"}, - {file = "asyncmy-0.2.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:625f96371d64769b94f7f7f699cfa5be56e669828aef3698cbf4f5bb0014ccb3"}, - {file = "asyncmy-0.2.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eeeb53fdd54eef54b9793a7a5c849c5f7a2fb2540a637f21585a996ef9dd8845"}, - {file = "asyncmy-0.2.9-cp38-cp38-win32.whl", hash = "sha256:2136b749ac489c25ab3aab4a81ae6e9dfb18fd0a5ebda96cd72788c5e4d46927"}, - {file = "asyncmy-0.2.9-cp38-cp38-win_amd64.whl", hash = "sha256:d08fb8722150a9c0645665cf777916335687bddb5f37a8e02af772e330be777b"}, - {file = "asyncmy-0.2.9-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:dbee276a9c8750b522aaad86315a6ed1ffbcb9145ce89070db77831c00dd2da1"}, - {file = "asyncmy-0.2.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8755248429f9bd3d7768c71494c9943fced18f9f526f768e96f5b9b3c727c84"}, - {file = "asyncmy-0.2.9-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:64bcd5110dca7a96cb411de85ab8f79fa867e864150939b8e76286a66eab28fc"}, - {file = "asyncmy-0.2.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a83e3895bed6d44aa334deb1c343d4ffc64b0def2215149f8df2e0e13499250"}, - {file = "asyncmy-0.2.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:beb3d0e434ce0bd9e609cf5341c3b82433ef544f89055d3792186e11fa2433d9"}, - {file = "asyncmy-0.2.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dc608ff331c5d1065e2d3566493d2d9e17f36e315bd5fad3c91c421eea306edb"}, - {file = "asyncmy-0.2.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:02caedc00035b2bd0be5555ef61d83ee9cb356ab488ac40072630ba224af02b0"}, - {file = "asyncmy-0.2.9-cp39-cp39-win32.whl", hash = "sha256:5b944d9cdf7ce25b396cd1e0c9319ba24c6583bde7a5dd31157614f3b9cc5b2f"}, - {file = "asyncmy-0.2.9-cp39-cp39-win_amd64.whl", hash = "sha256:3ceb59b9307b5eb893f4d473fcbc43ac0321ffb0436e0115b20cc2e0baa44eb5"}, - {file = "asyncmy-0.2.9-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9f1ca623517552a637900b90d65b5bafc9c67bebf96e3427eecb9359ffa24b1"}, - {file = "asyncmy-0.2.9-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:49622dc4ec69b5a4cbddb3695a1e9249b31092c6f19604abb664b43dcb509b6f"}, - {file = "asyncmy-0.2.9-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8412e825443ee876ef0d55ac4356b56173f5cb64ca8e4638974f8cf5c912a63"}, - {file = "asyncmy-0.2.9-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:4025db2a27b1d84d3c68b5d5aacecac17258b69f25ec8a8c350c5f666003a778"}, - {file = "asyncmy-0.2.9-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da7640f3357849b176364ed546908e28c8460701ddc0d23cc3fa7113ec52a076"}, - {file = "asyncmy-0.2.9-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:d2593717fa7a92a7d361444726292ce34edea76d5aa67d469b5efeee1c9b729e"}, - {file = "asyncmy-0.2.9-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9f22e13bd77277593b56de2e4b65c40c2e81b1a42c4845d062403c5c5bc52bc"}, - {file = "asyncmy-0.2.9-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a4aa17cc6ac0f7bc6b72e08d112566e69a36e2e1ebebad43d699757b7b4ff028"}, - {file = "asyncmy-0.2.9-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7e6f5205722e67c910510e294ad483bdafa7e29d5cf455d49ffa4b819e55fd8"}, - {file = "asyncmy-0.2.9-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:1021796f1910a0c2ab2d878f8f5d56f939ef0681f9c1fe925b78161cad2f8297"}, - {file = "asyncmy-0.2.9-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux_2_5_x86_64.manylinux1_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b1dd463bb054138bd1fd3fec9911eb618e92f54f61abb476658f863340394d1"}, - {file = "asyncmy-0.2.9-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ad06f3c02d455947e95087d29f7122411208f0eadaf8671772fe5bad97d9873a"}, - {file = "asyncmy-0.2.9.tar.gz", hash = "sha256:da188be013291d1f831d63cdd3614567f4c63bfdcde73631ddff8df00c56d614"}, -] - -[[package]] -name = "attrs" -version = "23.2.0" -description = "Classes Without Boilerplate" -optional = false -python-versions = ">=3.7" -files = [ - {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, - {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, -] - -[package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] -tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] - -[[package]] -name = "babel" -version = "2.14.0" -description = "Internationalization utilities" -optional = false -python-versions = ">=3.7" -files = [ - {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"}, - {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"}, -] - -[package.extras] -dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] - -[[package]] -name = "bcrypt" -version = "4.1.2" -description = "Modern password hashing for your software and your servers" -optional = false -python-versions = ">=3.7" -files = [ - {file = "bcrypt-4.1.2-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:ac621c093edb28200728a9cca214d7e838529e557027ef0581685909acd28b5e"}, - {file = "bcrypt-4.1.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea505c97a5c465ab8c3ba75c0805a102ce526695cd6818c6de3b1a38f6f60da1"}, - {file = "bcrypt-4.1.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57fa9442758da926ed33a91644649d3e340a71e2d0a5a8de064fb621fd5a3326"}, - {file = "bcrypt-4.1.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eb3bd3321517916696233b5e0c67fd7d6281f0ef48e66812db35fc963a422a1c"}, - {file = "bcrypt-4.1.2-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6cad43d8c63f34b26aef462b6f5e44fdcf9860b723d2453b5d391258c4c8e966"}, - {file = "bcrypt-4.1.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:44290ccc827d3a24604f2c8bcd00d0da349e336e6503656cb8192133e27335e2"}, - {file = "bcrypt-4.1.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:732b3920a08eacf12f93e6b04ea276c489f1c8fb49344f564cca2adb663b3e4c"}, - {file = "bcrypt-4.1.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1c28973decf4e0e69cee78c68e30a523be441972c826703bb93099868a8ff5b5"}, - {file = "bcrypt-4.1.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b8df79979c5bae07f1db22dcc49cc5bccf08a0380ca5c6f391cbb5790355c0b0"}, - {file = "bcrypt-4.1.2-cp37-abi3-win32.whl", hash = "sha256:fbe188b878313d01b7718390f31528be4010fed1faa798c5a1d0469c9c48c369"}, - {file = "bcrypt-4.1.2-cp37-abi3-win_amd64.whl", hash = "sha256:9800ae5bd5077b13725e2e3934aa3c9c37e49d3ea3d06318010aa40f54c63551"}, - {file = "bcrypt-4.1.2-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:71b8be82bc46cedd61a9f4ccb6c1a493211d031415a34adde3669ee1b0afbb63"}, - {file = "bcrypt-4.1.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e3c6642077b0c8092580c819c1684161262b2e30c4f45deb000c38947bf483"}, - {file = "bcrypt-4.1.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:387e7e1af9a4dd636b9505a465032f2f5cb8e61ba1120e79a0e1cd0b512f3dfc"}, - {file = "bcrypt-4.1.2-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f70d9c61f9c4ca7d57f3bfe88a5ccf62546ffbadf3681bb1e268d9d2e41c91a7"}, - {file = "bcrypt-4.1.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2a298db2a8ab20056120b45e86c00a0a5eb50ec4075b6142db35f593b97cb3fb"}, - {file = "bcrypt-4.1.2-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:ba55e40de38a24e2d78d34c2d36d6e864f93e0d79d0b6ce915e4335aa81d01b1"}, - {file = "bcrypt-4.1.2-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3566a88234e8de2ccae31968127b0ecccbb4cddb629da744165db72b58d88ca4"}, - {file = "bcrypt-4.1.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b90e216dc36864ae7132cb151ffe95155a37a14e0de3a8f64b49655dd959ff9c"}, - {file = "bcrypt-4.1.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:69057b9fc5093ea1ab00dd24ede891f3e5e65bee040395fb1e66ee196f9c9b4a"}, - {file = "bcrypt-4.1.2-cp39-abi3-win32.whl", hash = "sha256:02d9ef8915f72dd6daaef40e0baeef8a017ce624369f09754baf32bb32dba25f"}, - {file = "bcrypt-4.1.2-cp39-abi3-win_amd64.whl", hash = "sha256:be3ab1071662f6065899fe08428e45c16aa36e28bc42921c4901a191fda6ee42"}, - {file = "bcrypt-4.1.2-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d75fc8cd0ba23f97bae88a6ec04e9e5351ff3c6ad06f38fe32ba50cbd0d11946"}, - {file = "bcrypt-4.1.2-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:a97e07e83e3262599434816f631cc4c7ca2aa8e9c072c1b1a7fec2ae809a1d2d"}, - {file = "bcrypt-4.1.2-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e51c42750b7585cee7892c2614be0d14107fad9581d1738d954a262556dd1aab"}, - {file = "bcrypt-4.1.2-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ba4e4cc26610581a6329b3937e02d319f5ad4b85b074846bf4fef8a8cf51e7bb"}, - {file = "bcrypt-4.1.2.tar.gz", hash = "sha256:33313a1200a3ae90b75587ceac502b048b840fc69e7f7a0905b5f87fac7a1258"}, -] - -[package.extras] -tests = ["pytest (>=3.2.1,!=3.3.0)"] -typecheck = ["mypy"] - -[[package]] -name = "black" -version = "24.3.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"}, - {file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"}, - {file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"}, - {file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"}, - {file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"}, - {file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"}, - {file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"}, - {file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"}, - {file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"}, - {file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"}, - {file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"}, - {file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"}, - {file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"}, - {file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"}, - {file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"}, - {file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"}, - {file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"}, - {file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"}, - {file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"}, - {file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"}, - {file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"}, - {file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"}, -] - -[package.dependencies] -aiohttp = [ - {version = ">=3.7.4,<3.9.0 || >3.9.0", optional = true, markers = "sys_platform == \"win32\" and implementation_name == \"pypy\" and extra == \"d\""}, - {version = ">=3.7.4", optional = true, markers = "sys_platform != \"win32\" and extra == \"d\" or implementation_name != \"pypy\" and extra == \"d\""}, -] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "certifi" -version = "2024.2.2" -description = "Python package for providing Mozilla's CA Bundle." -optional = false -python-versions = ">=3.6" -files = [ - {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, - {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, -] - -[[package]] -name = "cffi" -version = "1.16.0" -description = "Foreign Function Interface for Python calling C code." -optional = false -python-versions = ">=3.8" -files = [ - {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, - {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, - {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, - {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, - {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, - {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, - {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, - {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, - {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, - {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, - {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, - {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, - {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, - {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, - {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, - {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, - {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, - {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, - {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, - {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, - {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, - {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, - {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, - {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, - {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, - {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, -] - -[package.dependencies] -pycparser = "*" - -[[package]] -name = "cfgv" -version = "3.4.0" -description = "Validate configuration and produce human readable error messages." -optional = false -python-versions = ">=3.8" -files = [ - {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, - {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, -] - -[[package]] -name = "charset-normalizer" -version = "3.3.2" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, -] - -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "coverage" -version = "7.4.4" -description = "Code coverage measurement for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "coverage-7.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2"}, - {file = "coverage-7.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf"}, - {file = "coverage-7.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8"}, - {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562"}, - {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2"}, - {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7"}, - {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87"}, - {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c"}, - {file = "coverage-7.4.4-cp310-cp310-win32.whl", hash = "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d"}, - {file = "coverage-7.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f"}, - {file = "coverage-7.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf"}, - {file = "coverage-7.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083"}, - {file = "coverage-7.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63"}, - {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f"}, - {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227"}, - {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd"}, - {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384"}, - {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b"}, - {file = "coverage-7.4.4-cp311-cp311-win32.whl", hash = "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286"}, - {file = "coverage-7.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec"}, - {file = "coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76"}, - {file = "coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818"}, - {file = "coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978"}, - {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70"}, - {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51"}, - {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c"}, - {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48"}, - {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9"}, - {file = "coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0"}, - {file = "coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e"}, - {file = "coverage-7.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384"}, - {file = "coverage-7.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1"}, - {file = "coverage-7.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a"}, - {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409"}, - {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e"}, - {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd"}, - {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7"}, - {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c"}, - {file = "coverage-7.4.4-cp38-cp38-win32.whl", hash = "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e"}, - {file = "coverage-7.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8"}, - {file = "coverage-7.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d"}, - {file = "coverage-7.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357"}, - {file = "coverage-7.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e"}, - {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e"}, - {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"}, - {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec"}, - {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd"}, - {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade"}, - {file = "coverage-7.4.4-cp39-cp39-win32.whl", hash = "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57"}, - {file = "coverage-7.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c"}, - {file = "coverage-7.4.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677"}, - {file = "coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49"}, -] - -[package.extras] -toml = ["tomli"] - -[[package]] -name = "coverage-badge" -version = "1.1.0" -description = "Generate coverage badges for Coverage.py." -optional = false -python-versions = "*" -files = [ - {file = "coverage-badge-1.1.0.tar.gz", hash = "sha256:c824a106503e981c02821e7d32f008fb3984b2338aa8c3800ec9357e33345b78"}, - {file = "coverage_badge-1.1.0-py2.py3-none-any.whl", hash = "sha256:e365d56e5202e923d1b237f82defd628a02d1d645a147f867ac85c58c81d7997"}, -] - -[package.dependencies] -coverage = "*" - -[[package]] -name = "cryptography" -version = "42.0.5" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -optional = false -python-versions = ">=3.7" -files = [ - {file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16"}, - {file = "cryptography-42.0.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278"}, - {file = "cryptography-42.0.5-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d"}, - {file = "cryptography-42.0.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da"}, - {file = "cryptography-42.0.5-cp37-abi3-win32.whl", hash = "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74"}, - {file = "cryptography-42.0.5-cp37-abi3-win_amd64.whl", hash = "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940"}, - {file = "cryptography-42.0.5-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc"}, - {file = "cryptography-42.0.5-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc"}, - {file = "cryptography-42.0.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30"}, - {file = "cryptography-42.0.5-cp39-abi3-win32.whl", hash = "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413"}, - {file = "cryptography-42.0.5-cp39-abi3-win_amd64.whl", hash = "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c"}, - {file = "cryptography-42.0.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac"}, - {file = "cryptography-42.0.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd"}, - {file = "cryptography-42.0.5.tar.gz", hash = "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1"}, -] - -[package.dependencies] -cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} - -[package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] -nox = ["nox"] -pep8test = ["check-sdist", "click", "mypy", "ruff"] -sdist = ["build"] -ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] -test-randomorder = ["pytest-randomly"] - -[[package]] -name = "deepdiff" -version = "6.7.1" -description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." -optional = false -python-versions = ">=3.7" -files = [ - {file = "deepdiff-6.7.1-py3-none-any.whl", hash = "sha256:58396bb7a863cbb4ed5193f548c56f18218060362311aa1dc36397b2f25108bd"}, - {file = "deepdiff-6.7.1.tar.gz", hash = "sha256:b367e6fa6caac1c9f500adc79ada1b5b1242c50d5f716a1a4362030197847d30"}, -] - -[package.dependencies] -ordered-set = ">=4.0.2,<4.2.0" - -[package.extras] -cli = ["click (==8.1.3)", "pyyaml (==6.0.1)"] -optimize = ["orjson"] - -[[package]] -name = "distlib" -version = "0.3.8" -description = "Distribution utilities" -optional = false -python-versions = "*" -files = [ - {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, - {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, -] - -[[package]] -name = "dnspython" -version = "2.6.1" -description = "DNS toolkit" -optional = false -python-versions = ">=3.8" -files = [ - {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, - {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, -] - -[package.extras] -dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] -dnssec = ["cryptography (>=41)"] -doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] -doq = ["aioquic (>=0.9.25)"] -idna = ["idna (>=3.6)"] -trio = ["trio (>=0.23)"] -wmi = ["wmi (>=1.5.1)"] - -[[package]] -name = "fastapi" -version = "0.110.0" -description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" -optional = false -python-versions = ">=3.8" -files = [ - {file = "fastapi-0.110.0-py3-none-any.whl", hash = "sha256:87a1f6fb632a218222c5984be540055346a8f5d8a68e8f6fb647b1dc9934de4b"}, - {file = "fastapi-0.110.0.tar.gz", hash = "sha256:266775f0dcc95af9d3ef39bad55cff525329a931d5fd51930aadd4f428bf7ff3"}, -] - -[package.dependencies] -pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -starlette = ">=0.36.3,<0.37.0" -typing-extensions = ">=4.8.0" - -[package.extras] -all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] - -[[package]] -name = "filelock" -version = "3.13.3" -description = "A platform independent file lock." -optional = false -python-versions = ">=3.8" -files = [ - {file = "filelock-3.13.3-py3-none-any.whl", hash = "sha256:5ffa845303983e7a0b7ae17636509bc97997d58afeafa72fb141a17b152284cb"}, - {file = "filelock-3.13.3.tar.gz", hash = "sha256:a79895a25bbefdf55d1a2a0a80968f7dbb28edcd6d4234a0afb3f37ecde4b546"}, -] - -[package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] -typing = ["typing-extensions (>=4.8)"] - -[[package]] -name = "frozenlist" -version = "1.4.1" -description = "A list-like structure which implements collections.abc.MutableSequence" -optional = false -python-versions = ">=3.8" -files = [ - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"}, - {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"}, - {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"}, - {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"}, - {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"}, - {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"}, - {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"}, - {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"}, - {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"}, - {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"}, - {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"}, - {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"}, - {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"}, - {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"}, - {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"}, - {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"}, - {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"}, - {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"}, - {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"}, - {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"}, - {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"}, - {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"}, - {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"}, - {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"}, - {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"}, - {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"}, - {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"}, - {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"}, -] - -[[package]] -name = "ghp-import" -version = "2.1.0" -description = "Copy your docs directly to the gh-pages branch." -optional = false -python-versions = "*" -files = [ - {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, - {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, -] - -[package.dependencies] -python-dateutil = ">=2.8.1" - -[package.extras] -dev = ["flake8", "markdown", "twine", "wheel"] - -[[package]] -name = "griffe" -version = "0.42.1" -description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." -optional = false -python-versions = ">=3.8" -files = [ - {file = "griffe-0.42.1-py3-none-any.whl", hash = "sha256:7e805e35617601355edcac0d3511cedc1ed0cb1f7645e2d336ae4b05bbae7b3b"}, - {file = "griffe-0.42.1.tar.gz", hash = "sha256:57046131384043ed078692b85d86b76568a686266cc036b9b56b704466f803ce"}, -] - -[package.dependencies] -colorama = ">=0.4" - -[[package]] -name = "h11" -version = "0.14.0" -description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -optional = false -python-versions = ">=3.7" -files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, -] - -[[package]] -name = "httpcore" -version = "1.0.4" -description = "A minimal low-level HTTP client." -optional = false -python-versions = ">=3.8" -files = [ - {file = "httpcore-1.0.4-py3-none-any.whl", hash = "sha256:ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73"}, - {file = "httpcore-1.0.4.tar.gz", hash = "sha256:cb2839ccfcba0d2d3c1131d3c3e26dfc327326fbe7a5dc0dbfe9f6c9151bb022"}, -] - -[package.dependencies] -certifi = "*" -h11 = ">=0.13,<0.15" - -[package.extras] -asyncio = ["anyio (>=4.0,<5.0)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.25.0)"] - -[[package]] -name = "httptools" -version = "0.6.1" -description = "A collection of framework independent HTTP protocol utils." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f"}, - {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563"}, - {file = "httptools-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58"}, - {file = "httptools-0.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185"}, - {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142"}, - {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658"}, - {file = "httptools-0.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b"}, - {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1"}, - {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0"}, - {file = "httptools-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc"}, - {file = "httptools-0.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2"}, - {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837"}, - {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d"}, - {file = "httptools-0.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3"}, - {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0"}, - {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2"}, - {file = "httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90"}, - {file = "httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503"}, - {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84"}, - {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb"}, - {file = "httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949"}, - {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8e216a038d2d52ea13fdd9b9c9c7459fb80d78302b257828285eca1c773b99b3"}, - {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e802e0b2378ade99cd666b5bffb8b2a7cc8f3d28988685dc300469ea8dd86cb"}, - {file = "httptools-0.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd3e488b447046e386a30f07af05f9b38d3d368d1f7b4d8f7e10af85393db97"}, - {file = "httptools-0.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe467eb086d80217b7584e61313ebadc8d187a4d95bb62031b7bab4b205c3ba3"}, - {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3c3b214ce057c54675b00108ac42bacf2ab8f85c58e3f324a4e963bbc46424f4"}, - {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ae5b97f690badd2ca27cbf668494ee1b6d34cf1c464271ef7bfa9ca6b83ffaf"}, - {file = "httptools-0.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:405784577ba6540fa7d6ff49e37daf104e04f4b4ff2d1ac0469eaa6a20fde084"}, - {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:95fb92dd3649f9cb139e9c56604cc2d7c7bf0fc2e7c8d7fbd58f96e35eddd2a3"}, - {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dcbab042cc3ef272adc11220517278519adf8f53fd3056d0e68f0a6f891ba94e"}, - {file = "httptools-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf2372e98406efb42e93bfe10f2948e467edfd792b015f1b4ecd897903d3e8d"}, - {file = "httptools-0.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:678fcbae74477a17d103b7cae78b74800d795d702083867ce160fc202104d0da"}, - {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e0b281cf5a125c35f7f6722b65d8542d2e57331be573e9e88bc8b0115c4a7a81"}, - {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:95658c342529bba4e1d3d2b1a874db16c7cca435e8827422154c9da76ac4e13a"}, - {file = "httptools-0.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ebaec1bf683e4bf5e9fbb49b8cc36da482033596a415b3e4ebab5a4c0d7ec5e"}, - {file = "httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a"}, -] - -[package.extras] -test = ["Cython (>=0.29.24,<0.30.0)"] - -[[package]] -name = "httpx" -version = "0.26.0" -description = "The next generation HTTP client." -optional = false -python-versions = ">=3.8" -files = [ - {file = "httpx-0.26.0-py3-none-any.whl", hash = "sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd"}, - {file = "httpx-0.26.0.tar.gz", hash = "sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf"}, -] - -[package.dependencies] -anyio = "*" -certifi = "*" -httpcore = "==1.*" -idna = "*" -sniffio = "*" - -[package.extras] -brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] -http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] - -[[package]] -name = "identify" -version = "2.5.35" -description = "File identification library for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "identify-2.5.35-py2.py3-none-any.whl", hash = "sha256:c4de0081837b211594f8e877a6b4fad7ca32bbfc1a9307fdd61c28bfe923f13e"}, - {file = "identify-2.5.35.tar.gz", hash = "sha256:10a7ca245cfcd756a554a7288159f72ff105ad233c7c4b9c6f0f4d108f5f6791"}, -] - -[package.extras] -license = ["ukkonen"] - -[[package]] -name = "idna" -version = "3.6" -description = "Internationalized Domain Names in Applications (IDNA)" -optional = false -python-versions = ">=3.5" -files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, -] - -[[package]] -name = "iniconfig" -version = "2.0.0" -description = "brain-dead simple config-ini parsing" -optional = false -python-versions = ">=3.7" -files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, -] - -[[package]] -name = "inject" -version = "5.2.1" -description = "Python dependency injection framework." -optional = false -python-versions = "*" -files = [ - {file = "inject-5.2.1-py2.py3-none-any.whl", hash = "sha256:e40a5b1bebd8a4050b6f98f3396f3de6e9e2e411ad2a2145f16f351cb6f54e51"}, - {file = "inject-5.2.1.tar.gz", hash = "sha256:f7c305a75cc4e3a331d248e996f25783ba784b88d5a9b9f73c53eacaa6d76985"}, -] - -[[package]] -name = "jinja2" -version = "3.1.3" -description = "A very fast and expressive template engine." -optional = false -python-versions = ">=3.7" -files = [ - {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, - {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, -] - -[package.dependencies] -MarkupSafe = ">=2.0" - -[package.extras] -i18n = ["Babel (>=2.7)"] - -[[package]] -name = "loguru" -version = "0.7.2" -description = "Python logging made (stupidly) simple" -optional = false -python-versions = ">=3.5" -files = [ - {file = "loguru-0.7.2-py3-none-any.whl", hash = "sha256:003d71e3d3ed35f0f8984898359d65b79e5b21943f78af86aa5491210429b8eb"}, - {file = "loguru-0.7.2.tar.gz", hash = "sha256:e671a53522515f34fd406340ee968cb9ecafbc4b36c679da03c18fd8d0bd51ac"}, -] - -[package.dependencies] -colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} -win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} - -[package.extras] -dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptiongroup (==1.1.3)", "freezegun (==1.1.0)", "freezegun (==1.2.2)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.4.1)", "mypy (==v1.5.1)", "pre-commit (==3.4.0)", "pytest (==6.1.2)", "pytest (==7.4.0)", "pytest-cov (==2.12.1)", "pytest-cov (==4.1.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.0.0)", "sphinx-autobuild (==2021.3.14)", "sphinx-rtd-theme (==1.3.0)", "tox (==3.27.1)", "tox (==4.11.0)"] - -[[package]] -name = "markdown" -version = "3.5.2" -description = "Python implementation of John Gruber's Markdown." -optional = false -python-versions = ">=3.8" -files = [ - {file = "Markdown-3.5.2-py3-none-any.whl", hash = "sha256:d43323865d89fc0cb9b20c75fc8ad313af307cc087e84b657d9eec768eddeadd"}, - {file = "Markdown-3.5.2.tar.gz", hash = "sha256:e1ac7b3dc550ee80e602e71c1d168002f062e49f1b11e26a36264dafd4df2ef8"}, -] - -[package.extras] -docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] -testing = ["coverage", "pyyaml"] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -description = "Python port of markdown-it. Markdown parsing, done right!" -optional = false -python-versions = ">=3.8" -files = [ - {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, - {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, -] - -[package.dependencies] -mdurl = ">=0.1,<1.0" - -[package.extras] -benchmarking = ["psutil", "pytest", "pytest-benchmark"] -code-style = ["pre-commit (>=3.0,<4.0)"] -compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] -linkify = ["linkify-it-py (>=1,<3)"] -plugins = ["mdit-py-plugins"] -profiling = ["gprof2dot"] -rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] - -[[package]] -name = "markupsafe" -version = "2.1.5" -description = "Safely add untrusted strings to HTML/XML markup." -optional = false -python-versions = ">=3.7" -files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -description = "Markdown URL utilities" -optional = false -python-versions = ">=3.7" -files = [ - {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, - {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, -] - -[[package]] -name = "mergedeep" -version = "1.3.4" -description = "A deep merge function for 🐍." -optional = false -python-versions = ">=3.6" -files = [ - {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, - {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, -] - -[[package]] -name = "mkdocs" -version = "1.5.3" -description = "Project documentation with Markdown." -optional = false -python-versions = ">=3.7" -files = [ - {file = "mkdocs-1.5.3-py3-none-any.whl", hash = "sha256:3b3a78e736b31158d64dbb2f8ba29bd46a379d0c6e324c2246c3bc3d2189cfc1"}, - {file = "mkdocs-1.5.3.tar.gz", hash = "sha256:eb7c99214dcb945313ba30426c2451b735992c73c2e10838f76d09e39ff4d0e2"}, -] - -[package.dependencies] -click = ">=7.0" -colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} -ghp-import = ">=1.0" -jinja2 = ">=2.11.1" -markdown = ">=3.2.1" -markupsafe = ">=2.0.1" -mergedeep = ">=1.3.4" -packaging = ">=20.5" -pathspec = ">=0.11.1" -platformdirs = ">=2.2.0" -pyyaml = ">=5.1" -pyyaml-env-tag = ">=0.1" -watchdog = ">=2.0" - -[package.extras] -i18n = ["babel (>=2.9.0)"] -min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pathspec (==0.11.1)", "platformdirs (==2.2.0)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"] - -[[package]] -name = "mkdocs-autorefs" -version = "1.0.1" -description = "Automatically link across pages in MkDocs." -optional = false -python-versions = ">=3.8" -files = [ - {file = "mkdocs_autorefs-1.0.1-py3-none-any.whl", hash = "sha256:aacdfae1ab197780fb7a2dac92ad8a3d8f7ca8049a9cbe56a4218cd52e8da570"}, - {file = "mkdocs_autorefs-1.0.1.tar.gz", hash = "sha256:f684edf847eced40b570b57846b15f0bf57fb93ac2c510450775dcf16accb971"}, -] - -[package.dependencies] -Markdown = ">=3.3" -markupsafe = ">=2.0.1" -mkdocs = ">=1.1" - -[[package]] -name = "mkdocs-material" -version = "9.5.15" -description = "Documentation that simply works" -optional = false -python-versions = ">=3.8" -files = [ - {file = "mkdocs_material-9.5.15-py3-none-any.whl", hash = "sha256:e5c96dec3d19491de49ca643fc1dbb92b278e43cdb816c775bc47db77d9b62fb"}, - {file = "mkdocs_material-9.5.15.tar.gz", hash = "sha256:39f03cca45e82bf54eb7456b5a18bd252eabfdd67f237a229471484a0a4d4635"}, -] - -[package.dependencies] -babel = ">=2.10,<3.0" -colorama = ">=0.4,<1.0" -jinja2 = ">=3.0,<4.0" -markdown = ">=3.2,<4.0" -mkdocs = ">=1.5.3,<1.6.0" -mkdocs-material-extensions = ">=1.3,<2.0" -paginate = ">=0.5,<1.0" -pygments = ">=2.16,<3.0" -pymdown-extensions = ">=10.2,<11.0" -regex = ">=2022.4" -requests = ">=2.26,<3.0" - -[package.extras] -git = ["mkdocs-git-committers-plugin-2 (>=1.1,<2.0)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4,<2.0)"] -imaging = ["cairosvg (>=2.6,<3.0)", "pillow (>=10.2,<11.0)"] -recommended = ["mkdocs-minify-plugin (>=0.7,<1.0)", "mkdocs-redirects (>=1.2,<2.0)", "mkdocs-rss-plugin (>=1.6,<2.0)"] - -[[package]] -name = "mkdocs-material-extensions" -version = "1.3.1" -description = "Extension pack for Python Markdown and MkDocs Material." -optional = false -python-versions = ">=3.8" -files = [ - {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, - {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, -] - -[[package]] -name = "mkdocs-monorepo-plugin" -version = "1.1.0" -description = "Plugin for adding monorepository support in Mkdocs." -optional = false -python-versions = ">=3" -files = [ - {file = "mkdocs-monorepo-plugin-1.1.0.tar.gz", hash = "sha256:ccc566e166aac5ae7fade498c15c4a337a4892d238629b51aba8ef3fc7099034"}, - {file = "mkdocs_monorepo_plugin-1.1.0-py3-none-any.whl", hash = "sha256:7bbfd9756a7fdecf64d6105dad96cce7e7bb5f0d6cfc2bfda31a1919c77cc3b9"}, -] - -[package.dependencies] -mkdocs = ">=1.0.4" -python-slugify = ">=4.0.1" - -[[package]] -name = "mkdocstrings" -version = "0.24.1" -description = "Automatic documentation from sources, for MkDocs." -optional = false -python-versions = ">=3.8" -files = [ - {file = "mkdocstrings-0.24.1-py3-none-any.whl", hash = "sha256:b4206f9a2ca8a648e222d5a0ca1d36ba7dee53c88732818de183b536f9042b5d"}, - {file = "mkdocstrings-0.24.1.tar.gz", hash = "sha256:cc83f9a1c8724fc1be3c2fa071dd73d91ce902ef6a79710249ec8d0ee1064401"}, -] - -[package.dependencies] -click = ">=7.0" -Jinja2 = ">=2.11.1" -Markdown = ">=3.3" -MarkupSafe = ">=1.1" -mkdocs = ">=1.4" -mkdocs-autorefs = ">=0.3.1" -platformdirs = ">=2.2.0" -pymdown-extensions = ">=6.3" - -[package.extras] -crystal = ["mkdocstrings-crystal (>=0.3.4)"] -python = ["mkdocstrings-python (>=0.5.2)"] -python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] - -[[package]] -name = "mkdocstrings-python" -version = "1.9.0" -description = "A Python handler for mkdocstrings." -optional = false -python-versions = ">=3.8" -files = [ - {file = "mkdocstrings_python-1.9.0-py3-none-any.whl", hash = "sha256:fad27d7314b4ec9c0359a187b477fb94c65ef561fdae941dca1b717c59aae96f"}, - {file = "mkdocstrings_python-1.9.0.tar.gz", hash = "sha256:6e1a442367cf75d30cf69774cbb1ad02aebec58bfff26087439df4955efecfde"}, -] - -[package.dependencies] -griffe = ">=0.37" -markdown = ">=3.3,<3.6" -mkdocstrings = ">=0.20" - -[[package]] -name = "multidict" -version = "6.0.5" -description = "multidict implementation" -optional = false -python-versions = ">=3.7" -files = [ - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"}, - {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"}, - {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"}, - {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"}, - {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"}, - {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"}, - {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"}, - {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"}, - {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"}, - {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"}, - {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"}, - {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"}, - {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"}, - {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"}, - {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"}, - {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"}, - {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"}, - {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"}, - {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"}, - {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"}, - {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"}, - {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"}, - {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"}, - {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"}, - {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"}, - {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"}, - {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"}, - {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"}, - {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"}, - {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"}, - {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"}, - {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"}, - {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"}, -] - -[[package]] -name = "mypy" -version = "1.9.0" -description = "Optional static typing for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "mypy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8a67616990062232ee4c3952f41c779afac41405806042a8126fe96e098419f"}, - {file = "mypy-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d357423fa57a489e8c47b7c85dfb96698caba13d66e086b412298a1a0ea3b0ed"}, - {file = "mypy-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c87c15aed320de9b438ae7b00c1ac91cd393c1b854c2ce538e2a72d55df150"}, - {file = "mypy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:48533cdd345c3c2e5ef48ba3b0d3880b257b423e7995dada04248725c6f77374"}, - {file = "mypy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:4d3dbd346cfec7cb98e6cbb6e0f3c23618af826316188d587d1c1bc34f0ede03"}, - {file = "mypy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:653265f9a2784db65bfca694d1edd23093ce49740b2244cde583aeb134c008f3"}, - {file = "mypy-1.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a3c007ff3ee90f69cf0a15cbcdf0995749569b86b6d2f327af01fd1b8aee9dc"}, - {file = "mypy-1.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2418488264eb41f69cc64a69a745fad4a8f86649af4b1041a4c64ee61fc61129"}, - {file = "mypy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:68edad3dc7d70f2f17ae4c6c1b9471a56138ca22722487eebacfd1eb5321d612"}, - {file = "mypy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:85ca5fcc24f0b4aeedc1d02f93707bccc04733f21d41c88334c5482219b1ccb3"}, - {file = "mypy-1.9.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aceb1db093b04db5cd390821464504111b8ec3e351eb85afd1433490163d60cd"}, - {file = "mypy-1.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0235391f1c6f6ce487b23b9dbd1327b4ec33bb93934aa986efe8a9563d9349e6"}, - {file = "mypy-1.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4d5ddc13421ba3e2e082a6c2d74c2ddb3979c39b582dacd53dd5d9431237185"}, - {file = "mypy-1.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:190da1ee69b427d7efa8aa0d5e5ccd67a4fb04038c380237a0d96829cb157913"}, - {file = "mypy-1.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:fe28657de3bfec596bbeef01cb219833ad9d38dd5393fc649f4b366840baefe6"}, - {file = "mypy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e54396d70be04b34f31d2edf3362c1edd023246c82f1730bbf8768c28db5361b"}, - {file = "mypy-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5e6061f44f2313b94f920e91b204ec600982961e07a17e0f6cd83371cb23f5c2"}, - {file = "mypy-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a10926e5473c5fc3da8abb04119a1f5811a236dc3a38d92015cb1e6ba4cb9e"}, - {file = "mypy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b685154e22e4e9199fc95f298661deea28aaede5ae16ccc8cbb1045e716b3e04"}, - {file = "mypy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:5d741d3fc7c4da608764073089e5f58ef6352bedc223ff58f2f038c2c4698a89"}, - {file = "mypy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:587ce887f75dd9700252a3abbc9c97bbe165a4a630597845c61279cf32dfbf02"}, - {file = "mypy-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f88566144752999351725ac623471661c9d1cd8caa0134ff98cceeea181789f4"}, - {file = "mypy-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61758fabd58ce4b0720ae1e2fea5cfd4431591d6d590b197775329264f86311d"}, - {file = "mypy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e49499be624dead83927e70c756970a0bc8240e9f769389cdf5714b0784ca6bf"}, - {file = "mypy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:571741dc4194b4f82d344b15e8837e8c5fcc462d66d076748142327626a1b6e9"}, - {file = "mypy-1.9.0-py3-none-any.whl", hash = "sha256:a260627a570559181a9ea5de61ac6297aa5af202f06fd7ab093ce74e7181e43e"}, - {file = "mypy-1.9.0.tar.gz", hash = "sha256:3cc5da0127e6a478cddd906068496a97a7618a21ce9b54bde5bf7e539c7af974"}, -] - -[package.dependencies] -mypy-extensions = ">=1.0.0" -typing-extensions = ">=4.1.0" - -[package.extras] -dmypy = ["psutil (>=4.0)"] -install-types = ["pip"] -mypyc = ["setuptools (>=50)"] -reports = ["lxml"] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[[package]] -name = "mysql-connector-python" -version = "8.3.0" -description = "MySQL driver written in Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "mysql-connector-python-8.3.0.tar.gz", hash = "sha256:e4ff23aa8036b4c5b6463fa81398bb5a528a29f99955de6ba937f0bba57a2fe3"}, - {file = "mysql_connector_python-8.3.0-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:f4ee7e07cca6b744874d60d6b0b24817d9246eb4e8d7269b7ddbe68763a0bd13"}, - {file = "mysql_connector_python-8.3.0-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:5718e426cf67f041772d4984f709052201883f74190ba6feaddce5cbd3b99e6f"}, - {file = "mysql_connector_python-8.3.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:0deb38f05057e12af091a48e03a1ff00e213945880000f802879fae5665e7502"}, - {file = "mysql_connector_python-8.3.0-cp310-cp310-manylinux_2_17_x86_64.whl", hash = "sha256:4be4165e4cd5acb4659261ddc74e9164d2dfa0d795d5695d52f2bf39ea0762fa"}, - {file = "mysql_connector_python-8.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:51d97bf771519829797556718d81e8b9bdcd0a00427740ca57c085094c8bde17"}, - {file = "mysql_connector_python-8.3.0-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:5e2c86c60be08c71bae755d811fe8b89ec4feb8117ec3440ebc6c042dd6f06bc"}, - {file = "mysql_connector_python-8.3.0-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:de74055944b214bff56e1752ec213d705c421414c67a250fb695af0c5c214135"}, - {file = "mysql_connector_python-8.3.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:b2901391b651d60dab3cc8985df94976fc1ea59fa7324c5b19d0a4177914c8dd"}, - {file = "mysql_connector_python-8.3.0-cp311-cp311-manylinux_2_17_x86_64.whl", hash = "sha256:55cb57d8098c721abce20fdef23232663977c0e5c87a4d0f9f73466f32c7d168"}, - {file = "mysql_connector_python-8.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:201e609159b84a247be87b76f5deb79e8c6b368e91f043790e62077f13f3fed8"}, - {file = "mysql_connector_python-8.3.0-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:c57d02fd6c28be444487e7905ede09e3fecb18377cf82908ca262826369d3401"}, - {file = "mysql_connector_python-8.3.0-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:9302d774025e76a0fac46bfeea8854b3d6819715a6a16ff23bfcda04218a76b7"}, - {file = "mysql_connector_python-8.3.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:85fa878fdd6accaeb7d609bd2637c2cfa61592e7f9bdbdc0da18b2fa998d3d5a"}, - {file = "mysql_connector_python-8.3.0-cp312-cp312-manylinux_2_17_x86_64.whl", hash = "sha256:de0f2f2baa9e091ca8bdc4a091f874f9cd0b84b256389596adb0e032a05fe9f9"}, - {file = "mysql_connector_python-8.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:27f8be2087627366a44a6831ec68b568c98dbf0f4ceff24682d90c21db6e0f1f"}, - {file = "mysql_connector_python-8.3.0-cp38-cp38-macosx_13_0_x86_64.whl", hash = "sha256:ec6dc3434a7deef74ab04e8978f6c5e181866a5423006c1b5aec5390a189d28d"}, - {file = "mysql_connector_python-8.3.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:73ee8bc5f9626c42b37342a91a825cddb3461f6bfbbd6524d8ccfd3293aaa088"}, - {file = "mysql_connector_python-8.3.0-cp38-cp38-manylinux_2_17_x86_64.whl", hash = "sha256:1db5b48b4ff7d24344217ed2418b162c7677eec86ab9766dc0e5feae39c90974"}, - {file = "mysql_connector_python-8.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:77bae496566d3da77bb0e938d89243103d20ee41633f626a47785470451bf45c"}, - {file = "mysql_connector_python-8.3.0-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:f7acacdf9fd4260702f360c00952ad9a9cc73e8b7475e0d0c973c085a3dd7b7d"}, - {file = "mysql_connector_python-8.3.0-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:5f707a9b040ad4700fc447ba955c78b08f2dd5affde37ac2401918f7b6daaba3"}, - {file = "mysql_connector_python-8.3.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:125714c998a697592bc56cce918a1acc58fadc510a7f588dbef3e53a1920e086"}, - {file = "mysql_connector_python-8.3.0-cp39-cp39-manylinux_2_17_x86_64.whl", hash = "sha256:7f4f5fa844c19ee3a78c4606f6e138b06829e75469592d90246a290c7befc322"}, - {file = "mysql_connector_python-8.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:de5c3ee89d9276356f93df003949d3ba4c486f32fec9ec9fd7bc0caab124d89c"}, - {file = "mysql_connector_python-8.3.0-py2.py3-none-any.whl", hash = "sha256:e868ccc7ad9fbc242546db04673d89cee87d12b8139affd114524553df4e5d6a"}, -] - -[package.extras] -dns-srv = ["dnspython (>=1.16.0,<=2.3.0)"] -fido2 = ["fido2 (==1.1.2)"] -gssapi = ["gssapi (>=1.6.9,<=1.8.2)"] -opentelemetry = ["Deprecated (>=1.2.6)", "typing-extensions (>=3.7.4)", "zipp (>=0.5)"] - -[[package]] -name = "nodeenv" -version = "1.8.0" -description = "Node.js virtual environment builder" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" -files = [ - {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, - {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, -] - -[package.dependencies] -setuptools = "*" - -[[package]] -name = "ordered-set" -version = "4.1.0" -description = "An OrderedSet is a custom MutableSet that remembers its order, so that every" -optional = false -python-versions = ">=3.7" -files = [ - {file = "ordered-set-4.1.0.tar.gz", hash = "sha256:694a8e44c87657c59292ede72891eb91d34131f6531463aab3009191c77364a8"}, - {file = "ordered_set-4.1.0-py3-none-any.whl", hash = "sha256:046e1132c71fcf3330438a539928932caf51ddbc582496833e23de611de14562"}, -] - -[package.extras] -dev = ["black", "mypy", "pytest"] - -[[package]] -name = "packaging" -version = "24.0" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.7" -files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, -] - -[[package]] -name = "paginate" -version = "0.5.6" -description = "Divides large result sets into pages for easier browsing" -optional = false -python-versions = "*" -files = [ - {file = "paginate-0.5.6.tar.gz", hash = "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"}, -] - -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - -[[package]] -name = "pendulum" -version = "3.0.0" -description = "Python datetimes made easy" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pendulum-3.0.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2cf9e53ef11668e07f73190c805dbdf07a1939c3298b78d5a9203a86775d1bfd"}, - {file = "pendulum-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fb551b9b5e6059377889d2d878d940fd0bbb80ae4810543db18e6f77b02c5ef6"}, - {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c58227ac260d5b01fc1025176d7b31858c9f62595737f350d22124a9a3ad82d"}, - {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60fb6f415fea93a11c52578eaa10594568a6716602be8430b167eb0d730f3332"}, - {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b69f6b4dbcb86f2c2fe696ba991e67347bcf87fe601362a1aba6431454b46bde"}, - {file = "pendulum-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:138afa9c373ee450ede206db5a5e9004fd3011b3c6bbe1e57015395cd076a09f"}, - {file = "pendulum-3.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:83d9031f39c6da9677164241fd0d37fbfc9dc8ade7043b5d6d62f56e81af8ad2"}, - {file = "pendulum-3.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0c2308af4033fa534f089595bcd40a95a39988ce4059ccd3dc6acb9ef14ca44a"}, - {file = "pendulum-3.0.0-cp310-none-win_amd64.whl", hash = "sha256:9a59637cdb8462bdf2dbcb9d389518c0263799189d773ad5c11db6b13064fa79"}, - {file = "pendulum-3.0.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3725245c0352c95d6ca297193192020d1b0c0f83d5ee6bb09964edc2b5a2d508"}, - {file = "pendulum-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6c035f03a3e565ed132927e2c1b691de0dbf4eb53b02a5a3c5a97e1a64e17bec"}, - {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597e66e63cbd68dd6d58ac46cb7a92363d2088d37ccde2dae4332ef23e95cd00"}, - {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99a0f8172e19f3f0c0e4ace0ad1595134d5243cf75985dc2233e8f9e8de263ca"}, - {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:77d8839e20f54706aed425bec82a83b4aec74db07f26acd039905d1237a5e1d4"}, - {file = "pendulum-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afde30e8146292b059020fbc8b6f8fd4a60ae7c5e6f0afef937bbb24880bdf01"}, - {file = "pendulum-3.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:660434a6fcf6303c4efd36713ca9212c753140107ee169a3fc6c49c4711c2a05"}, - {file = "pendulum-3.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dee9e5a48c6999dc1106eb7eea3e3a50e98a50651b72c08a87ee2154e544b33e"}, - {file = "pendulum-3.0.0-cp311-none-win_amd64.whl", hash = "sha256:d4cdecde90aec2d67cebe4042fd2a87a4441cc02152ed7ed8fb3ebb110b94ec4"}, - {file = "pendulum-3.0.0-cp311-none-win_arm64.whl", hash = "sha256:773c3bc4ddda2dda9f1b9d51fe06762f9200f3293d75c4660c19b2614b991d83"}, - {file = "pendulum-3.0.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:409e64e41418c49f973d43a28afe5df1df4f1dd87c41c7c90f1a63f61ae0f1f7"}, - {file = "pendulum-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a38ad2121c5ec7c4c190c7334e789c3b4624798859156b138fcc4d92295835dc"}, - {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fde4d0b2024b9785f66b7f30ed59281bd60d63d9213cda0eb0910ead777f6d37"}, - {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4b2c5675769fb6d4c11238132962939b960fcb365436b6d623c5864287faa319"}, - {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8af95e03e066826f0f4c65811cbee1b3123d4a45a1c3a2b4fc23c4b0dff893b5"}, - {file = "pendulum-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2165a8f33cb15e06c67070b8afc87a62b85c5a273e3aaa6bc9d15c93a4920d6f"}, - {file = "pendulum-3.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ad5e65b874b5e56bd942546ea7ba9dd1d6a25121db1c517700f1c9de91b28518"}, - {file = "pendulum-3.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17fe4b2c844bbf5f0ece69cfd959fa02957c61317b2161763950d88fed8e13b9"}, - {file = "pendulum-3.0.0-cp312-none-win_amd64.whl", hash = "sha256:78f8f4e7efe5066aca24a7a57511b9c2119f5c2b5eb81c46ff9222ce11e0a7a5"}, - {file = "pendulum-3.0.0-cp312-none-win_arm64.whl", hash = "sha256:28f49d8d1e32aae9c284a90b6bb3873eee15ec6e1d9042edd611b22a94ac462f"}, - {file = "pendulum-3.0.0-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:d4e2512f4e1a4670284a153b214db9719eb5d14ac55ada5b76cbdb8c5c00399d"}, - {file = "pendulum-3.0.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:3d897eb50883cc58d9b92f6405245f84b9286cd2de6e8694cb9ea5cb15195a32"}, - {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e169cc2ca419517f397811bbe4589cf3cd13fca6dc38bb352ba15ea90739ebb"}, - {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f17c3084a4524ebefd9255513692f7e7360e23c8853dc6f10c64cc184e1217ab"}, - {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:826d6e258052715f64d05ae0fc9040c0151e6a87aae7c109ba9a0ed930ce4000"}, - {file = "pendulum-3.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2aae97087872ef152a0c40e06100b3665d8cb86b59bc8471ca7c26132fccd0f"}, - {file = "pendulum-3.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ac65eeec2250d03106b5e81284ad47f0d417ca299a45e89ccc69e36130ca8bc7"}, - {file = "pendulum-3.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a5346d08f3f4a6e9e672187faa179c7bf9227897081d7121866358af369f44f9"}, - {file = "pendulum-3.0.0-cp37-none-win_amd64.whl", hash = "sha256:235d64e87946d8f95c796af34818c76e0f88c94d624c268693c85b723b698aa9"}, - {file = "pendulum-3.0.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:6a881d9c2a7f85bc9adafcfe671df5207f51f5715ae61f5d838b77a1356e8b7b"}, - {file = "pendulum-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d7762d2076b9b1cb718a6631ad6c16c23fc3fac76cbb8c454e81e80be98daa34"}, - {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e8e36a8130819d97a479a0e7bf379b66b3b1b520e5dc46bd7eb14634338df8c"}, - {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7dc843253ac373358ffc0711960e2dd5b94ab67530a3e204d85c6e8cb2c5fa10"}, - {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a78ad3635d609ceb1e97d6aedef6a6a6f93433ddb2312888e668365908c7120"}, - {file = "pendulum-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b30a137e9e0d1f751e60e67d11fc67781a572db76b2296f7b4d44554761049d6"}, - {file = "pendulum-3.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c95984037987f4a457bb760455d9ca80467be792236b69d0084f228a8ada0162"}, - {file = "pendulum-3.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d29c6e578fe0f893766c0d286adbf0b3c726a4e2341eba0917ec79c50274ec16"}, - {file = "pendulum-3.0.0-cp38-none-win_amd64.whl", hash = "sha256:deaba8e16dbfcb3d7a6b5fabdd5a38b7c982809567479987b9c89572df62e027"}, - {file = "pendulum-3.0.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b11aceea5b20b4b5382962b321dbc354af0defe35daa84e9ff3aae3c230df694"}, - {file = "pendulum-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a90d4d504e82ad236afac9adca4d6a19e4865f717034fc69bafb112c320dcc8f"}, - {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:825799c6b66e3734227756fa746cc34b3549c48693325b8b9f823cb7d21b19ac"}, - {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad769e98dc07972e24afe0cff8d365cb6f0ebc7e65620aa1976fcfbcadc4c6f3"}, - {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6fc26907eb5fb8cc6188cc620bc2075a6c534d981a2f045daa5f79dfe50d512"}, - {file = "pendulum-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c717eab1b6d898c00a3e0fa7781d615b5c5136bbd40abe82be100bb06df7a56"}, - {file = "pendulum-3.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3ddd1d66d1a714ce43acfe337190be055cdc221d911fc886d5a3aae28e14b76d"}, - {file = "pendulum-3.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:822172853d7a9cf6da95d7b66a16c7160cb99ae6df55d44373888181d7a06edc"}, - {file = "pendulum-3.0.0-cp39-none-win_amd64.whl", hash = "sha256:840de1b49cf1ec54c225a2a6f4f0784d50bd47f68e41dc005b7f67c7d5b5f3ae"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3b1f74d1e6ffe5d01d6023870e2ce5c2191486928823196f8575dcc786e107b1"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:729e9f93756a2cdfa77d0fc82068346e9731c7e884097160603872686e570f07"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e586acc0b450cd21cbf0db6bae386237011b75260a3adceddc4be15334689a9a"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22e7944ffc1f0099a79ff468ee9630c73f8c7835cd76fdb57ef7320e6a409df4"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fa30af36bd8e50686846bdace37cf6707bdd044e5cb6e1109acbad3277232e04"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:440215347b11914ae707981b9a57ab9c7b6983ab0babde07063c6ee75c0dc6e7"}, - {file = "pendulum-3.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:314c4038dc5e6a52991570f50edb2f08c339debdf8cea68ac355b32c4174e820"}, - {file = "pendulum-3.0.0-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5acb1d386337415f74f4d1955c4ce8d0201978c162927d07df8eb0692b2d8533"}, - {file = "pendulum-3.0.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a789e12fbdefaffb7b8ac67f9d8f22ba17a3050ceaaa635cd1cc4645773a4b1e"}, - {file = "pendulum-3.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:860aa9b8a888e5913bd70d819306749e5eb488e6b99cd6c47beb701b22bdecf5"}, - {file = "pendulum-3.0.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:5ebc65ea033ef0281368217fbf59f5cb05b338ac4dd23d60959c7afcd79a60a0"}, - {file = "pendulum-3.0.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d9fef18ab0386ef6a9ac7bad7e43ded42c83ff7ad412f950633854f90d59afa8"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1c134ba2f0571d0b68b83f6972e2307a55a5a849e7dac8505c715c531d2a8795"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:385680812e7e18af200bb9b4a49777418c32422d05ad5a8eb85144c4a285907b"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eec91cd87c59fb32ec49eb722f375bd58f4be790cae11c1b70fac3ee4f00da0"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4386bffeca23c4b69ad50a36211f75b35a4deb6210bdca112ac3043deb7e494a"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dfbcf1661d7146d7698da4b86e7f04814221081e9fe154183e34f4c5f5fa3bf8"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:04a1094a5aa1daa34a6b57c865b25f691848c61583fb22722a4df5699f6bf74c"}, - {file = "pendulum-3.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5b0ec85b9045bd49dd3a3493a5e7ddfd31c36a2a60da387c419fa04abcaecb23"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0a15b90129765b705eb2039062a6daf4d22c4e28d1a54fa260892e8c3ae6e157"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:bb8f6d7acd67a67d6fedd361ad2958ff0539445ef51cbe8cd288db4306503cd0"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd69b15374bef7e4b4440612915315cc42e8575fcda2a3d7586a0d88192d0c88"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc00f8110db6898360c53c812872662e077eaf9c75515d53ecc65d886eec209a"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:83a44e8b40655d0ba565a5c3d1365d27e3e6778ae2a05b69124db9e471255c4a"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:1a3604e9fbc06b788041b2a8b78f75c243021e0f512447806a6d37ee5214905d"}, - {file = "pendulum-3.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:92c307ae7accebd06cbae4729f0ba9fa724df5f7d91a0964b1b972a22baa482b"}, - {file = "pendulum-3.0.0.tar.gz", hash = "sha256:5d034998dea404ec31fae27af6b22cff1708f830a1ed7353be4d1019bb9f584e"}, -] - -[package.dependencies] -python-dateutil = ">=2.6" -time-machine = {version = ">=2.6.0", optional = true, markers = "implementation_name != \"pypy\" and extra == \"test\""} -tzdata = ">=2020.1" - -[package.extras] -test = ["time-machine (>=2.6.0)"] - -[[package]] -name = "platformdirs" -version = "4.2.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -optional = false -python-versions = ">=3.8" -files = [ - {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, - {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, -] - -[package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] - -[[package]] -name = "pluggy" -version = "1.4.0" -description = "plugin and hook calling mechanisms for python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, - {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, -] - -[package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "pre-commit" -version = "3.7.0" -description = "A framework for managing and maintaining multi-language pre-commit hooks." -optional = false -python-versions = ">=3.9" -files = [ - {file = "pre_commit-3.7.0-py2.py3-none-any.whl", hash = "sha256:5eae9e10c2b5ac51577c3452ec0a490455c45a0533f7960f993a0d01e59decab"}, - {file = "pre_commit-3.7.0.tar.gz", hash = "sha256:e209d61b8acdcf742404408531f0c37d49d2c734fd7cff2d6076083d191cb060"}, -] - -[package.dependencies] -cfgv = ">=2.0.0" -identify = ">=1.0.0" -nodeenv = ">=0.11.1" -pyyaml = ">=5.1" -virtualenv = ">=20.10.0" - -[[package]] -name = "pycparser" -version = "2.21" -description = "C parser in Python" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, -] - -[[package]] -name = "pydantic" -version = "2.6.3" -description = "Data validation using Python type hints" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pydantic-2.6.3-py3-none-any.whl", hash = "sha256:72c6034df47f46ccdf81869fddb81aade68056003900a8724a4f160700016a2a"}, - {file = "pydantic-2.6.3.tar.gz", hash = "sha256:e07805c4c7f5c6826e33a1d4c9d47950d7eaf34868e2690f8594d2e30241f11f"}, -] - -[package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.16.3" -typing-extensions = ">=4.6.1" - -[package.extras] -email = ["email-validator (>=2.0.0)"] - -[[package]] -name = "pydantic-core" -version = "2.16.3" -description = "" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, - {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, - {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, - {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, - {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, - {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, - {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, - {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, - {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, - {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, - {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, - {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, - {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, - {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, -] - -[package.dependencies] -typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" - -[[package]] -name = "pygments" -version = "2.17.2" -description = "Pygments is a syntax highlighting package written in Python." -optional = false -python-versions = ">=3.7" -files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, -] - -[package.extras] -plugins = ["importlib-metadata"] -windows-terminal = ["colorama (>=0.4.6)"] - -[[package]] -name = "pyisemail" -version = "2.0.1" -description = "Simple, robust email validation" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pyisemail-2.0.1-py3-none-any.whl", hash = "sha256:3d2bebd159f436673219d024a3f02bed1b468c793df9a5fa08d72b7d4b4f6cb4"}, - {file = "pyisemail-2.0.1.tar.gz", hash = "sha256:daf4b3fb2150a38f406b0aaba729e19fcd638a6d1c0549c25ff54c7b804618f8"}, -] - -[package.dependencies] -dnspython = ">=2.0.0" - -[[package]] -name = "pyjwt" -version = "2.8.0" -description = "JSON Web Token implementation in Python" -optional = false -python-versions = ">=3.7" -files = [ - {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, - {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, -] - -[package.extras] -crypto = ["cryptography (>=3.4.0)"] -dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] -docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] -tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] - -[[package]] -name = "pymdown-extensions" -version = "10.7.1" -description = "Extension pack for Python Markdown." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pymdown_extensions-10.7.1-py3-none-any.whl", hash = "sha256:f5cc7000d7ff0d1ce9395d216017fa4df3dde800afb1fb72d1c7d3fd35e710f4"}, - {file = "pymdown_extensions-10.7.1.tar.gz", hash = "sha256:c70e146bdd83c744ffc766b4671999796aba18842b268510a329f7f64700d584"}, -] - -[package.dependencies] -markdown = ">=3.5" -pyyaml = "*" - -[package.extras] -extra = ["pygments (>=2.12)"] - -[[package]] -name = "pytest" -version = "8.1.1" -description = "pytest: simple powerful testing with Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7"}, - {file = "pytest-8.1.1.tar.gz", hash = "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -iniconfig = "*" -packaging = "*" -pluggy = ">=1.4,<2.0" - -[package.extras] -testing = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] - -[[package]] -name = "pytest-asyncio" -version = "0.21.1" -description = "Pytest support for asyncio" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"}, - {file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"}, -] - -[package.dependencies] -pytest = ">=7.0.0" - -[package.extras] -docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] -testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] - -[[package]] -name = "pytest-cov" -version = "5.0.0" -description = "Pytest plugin for measuring coverage." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, - {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, -] - -[package.dependencies] -coverage = {version = ">=5.2.1", extras = ["toml"]} -pytest = ">=4.6" - -[package.extras] -testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] - -[[package]] -name = "pytest-sugar" -version = "1.0.0" -description = "pytest-sugar is a plugin for pytest that changes the default look and feel of pytest (e.g. progressbar, show tests that fail instantly)." -optional = false -python-versions = "*" -files = [ - {file = "pytest-sugar-1.0.0.tar.gz", hash = "sha256:6422e83258f5b0c04ce7c632176c7732cab5fdb909cb39cca5c9139f81276c0a"}, - {file = "pytest_sugar-1.0.0-py3-none-any.whl", hash = "sha256:70ebcd8fc5795dc457ff8b69d266a4e2e8a74ae0c3edc749381c64b5246c8dfd"}, -] - -[package.dependencies] -packaging = ">=21.3" -pytest = ">=6.2.0" -termcolor = ">=2.1.0" - -[package.extras] -dev = ["black", "flake8", "pre-commit"] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -description = "Extensions to the standard Python datetime module" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" -files = [ - {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, - {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "python-dotenv" -version = "1.0.1" -description = "Read key-value pairs from a .env file and set them as environment variables" -optional = false -python-versions = ">=3.8" -files = [ - {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, - {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, -] - -[package.extras] -cli = ["click (>=5.0)"] - -[[package]] -name = "python-multipart" -version = "0.0.9" -description = "A streaming multipart parser for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "python_multipart-0.0.9-py3-none-any.whl", hash = "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"}, - {file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"}, -] - -[package.extras] -dev = ["atomicwrites (==1.4.1)", "attrs (==23.2.0)", "coverage (==7.4.1)", "hatch", "invoke (==2.2.0)", "more-itertools (==10.2.0)", "pbr (==6.0.0)", "pluggy (==1.4.0)", "py (==1.11.0)", "pytest (==8.0.0)", "pytest-cov (==4.1.0)", "pytest-timeout (==2.2.0)", "pyyaml (==6.0.1)", "ruff (==0.2.1)"] - -[[package]] -name = "python-slugify" -version = "8.0.4" -description = "A Python slugify application that also handles Unicode" -optional = false -python-versions = ">=3.7" -files = [ - {file = "python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856"}, - {file = "python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8"}, -] - -[package.dependencies] -text-unidecode = ">=1.3" - -[package.extras] -unidecode = ["Unidecode (>=1.1.1)"] - -[[package]] -name = "pyyaml" -version = "6.0.1" -description = "YAML parser and emitter for Python" -optional = false -python-versions = ">=3.6" -files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, -] - -[[package]] -name = "pyyaml-env-tag" -version = "0.1" -description = "A custom YAML tag for referencing environment variables in YAML files. " -optional = false -python-versions = ">=3.6" -files = [ - {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, - {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, -] - -[package.dependencies] -pyyaml = "*" - -[[package]] -name = "redis" -version = "5.0.3" -description = "Python client for Redis database and key-value store" -optional = false -python-versions = ">=3.7" -files = [ - {file = "redis-5.0.3-py3-none-any.whl", hash = "sha256:5da9b8fe9e1254293756c16c008e8620b3d15fcc6dde6babde9541850e72a32d"}, - {file = "redis-5.0.3.tar.gz", hash = "sha256:4973bae7444c0fbed64a06b87446f79361cb7e4ec1538c022d696ed7a5015580"}, -] - -[package.extras] -hiredis = ["hiredis (>=1.0.0)"] -ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] - -[[package]] -name = "regex" -version = "2023.12.25" -description = "Alternative regular expression module, to replace re." -optional = false -python-versions = ">=3.7" -files = [ - {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0694219a1d54336fd0445ea382d49d36882415c0134ee1e8332afd1529f0baa5"}, - {file = "regex-2023.12.25-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b014333bd0217ad3d54c143de9d4b9a3ca1c5a29a6d0d554952ea071cff0f1f8"}, - {file = "regex-2023.12.25-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d865984b3f71f6d0af64d0d88f5733521698f6c16f445bb09ce746c92c97c586"}, - {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e0eabac536b4cc7f57a5f3d095bfa557860ab912f25965e08fe1545e2ed8b4c"}, - {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c25a8ad70e716f96e13a637802813f65d8a6760ef48672aa3502f4c24ea8b400"}, - {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9b6d73353f777630626f403b0652055ebfe8ff142a44ec2cf18ae470395766e"}, - {file = "regex-2023.12.25-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9cc99d6946d750eb75827cb53c4371b8b0fe89c733a94b1573c9dd16ea6c9e4"}, - {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88d1f7bef20c721359d8675f7d9f8e414ec5003d8f642fdfd8087777ff7f94b5"}, - {file = "regex-2023.12.25-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cb3fe77aec8f1995611f966d0c656fdce398317f850d0e6e7aebdfe61f40e1cd"}, - {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7aa47c2e9ea33a4a2a05f40fcd3ea36d73853a2aae7b4feab6fc85f8bf2c9704"}, - {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:df26481f0c7a3f8739fecb3e81bc9da3fcfae34d6c094563b9d4670b047312e1"}, - {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c40281f7d70baf6e0db0c2f7472b31609f5bc2748fe7275ea65a0b4601d9b392"}, - {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:d94a1db462d5690ebf6ae86d11c5e420042b9898af5dcf278bd97d6bda065423"}, - {file = "regex-2023.12.25-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ba1b30765a55acf15dce3f364e4928b80858fa8f979ad41f862358939bdd1f2f"}, - {file = "regex-2023.12.25-cp310-cp310-win32.whl", hash = "sha256:150c39f5b964e4d7dba46a7962a088fbc91f06e606f023ce57bb347a3b2d4630"}, - {file = "regex-2023.12.25-cp310-cp310-win_amd64.whl", hash = "sha256:09da66917262d9481c719599116c7dc0c321ffcec4b1f510c4f8a066f8768105"}, - {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1b9d811f72210fa9306aeb88385b8f8bcef0dfbf3873410413c00aa94c56c2b6"}, - {file = "regex-2023.12.25-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d902a43085a308cef32c0d3aea962524b725403fd9373dea18110904003bac97"}, - {file = "regex-2023.12.25-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d166eafc19f4718df38887b2bbe1467a4f74a9830e8605089ea7a30dd4da8887"}, - {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7ad32824b7f02bb3c9f80306d405a1d9b7bb89362d68b3c5a9be53836caebdb"}, - {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:636ba0a77de609d6510235b7f0e77ec494d2657108f777e8765efc060094c98c"}, - {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fda75704357805eb953a3ee15a2b240694a9a514548cd49b3c5124b4e2ad01b"}, - {file = "regex-2023.12.25-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f72cbae7f6b01591f90814250e636065850c5926751af02bb48da94dfced7baa"}, - {file = "regex-2023.12.25-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db2a0b1857f18b11e3b0e54ddfefc96af46b0896fb678c85f63fb8c37518b3e7"}, - {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7502534e55c7c36c0978c91ba6f61703faf7ce733715ca48f499d3dbbd7657e0"}, - {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e8c7e08bb566de4faaf11984af13f6bcf6a08f327b13631d41d62592681d24fe"}, - {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:283fc8eed679758de38fe493b7d7d84a198b558942b03f017b1f94dda8efae80"}, - {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f44dd4d68697559d007462b0a3a1d9acd61d97072b71f6d1968daef26bc744bd"}, - {file = "regex-2023.12.25-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:67d3ccfc590e5e7197750fcb3a2915b416a53e2de847a728cfa60141054123d4"}, - {file = "regex-2023.12.25-cp311-cp311-win32.whl", hash = "sha256:68191f80a9bad283432385961d9efe09d783bcd36ed35a60fb1ff3f1ec2efe87"}, - {file = "regex-2023.12.25-cp311-cp311-win_amd64.whl", hash = "sha256:7d2af3f6b8419661a0c421584cfe8aaec1c0e435ce7e47ee2a97e344b98f794f"}, - {file = "regex-2023.12.25-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8a0ccf52bb37d1a700375a6b395bff5dd15c50acb745f7db30415bae3c2b0715"}, - {file = "regex-2023.12.25-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c3c4a78615b7762740531c27cf46e2f388d8d727d0c0c739e72048beb26c8a9d"}, - {file = "regex-2023.12.25-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ad83e7545b4ab69216cef4cc47e344d19622e28aabec61574b20257c65466d6a"}, - {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7a635871143661feccce3979e1727c4e094f2bdfd3ec4b90dfd4f16f571a87a"}, - {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d498eea3f581fbe1b34b59c697512a8baef88212f92e4c7830fcc1499f5b45a5"}, - {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:43f7cd5754d02a56ae4ebb91b33461dc67be8e3e0153f593c509e21d219c5060"}, - {file = "regex-2023.12.25-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51f4b32f793812714fd5307222a7f77e739b9bc566dc94a18126aba3b92b98a3"}, - {file = "regex-2023.12.25-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba99d8077424501b9616b43a2d208095746fb1284fc5ba490139651f971d39d9"}, - {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4bfc2b16e3ba8850e0e262467275dd4d62f0d045e0e9eda2bc65078c0110a11f"}, - {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8c2c19dae8a3eb0ea45a8448356ed561be843b13cbc34b840922ddf565498c1c"}, - {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:60080bb3d8617d96f0fb7e19796384cc2467447ef1c491694850ebd3670bc457"}, - {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b77e27b79448e34c2c51c09836033056a0547aa360c45eeeb67803da7b0eedaf"}, - {file = "regex-2023.12.25-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:518440c991f514331f4850a63560321f833979d145d7d81186dbe2f19e27ae3d"}, - {file = "regex-2023.12.25-cp312-cp312-win32.whl", hash = "sha256:e2610e9406d3b0073636a3a2e80db05a02f0c3169b5632022b4e81c0364bcda5"}, - {file = "regex-2023.12.25-cp312-cp312-win_amd64.whl", hash = "sha256:cc37b9aeebab425f11f27e5e9e6cf580be7206c6582a64467a14dda211abc232"}, - {file = "regex-2023.12.25-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:da695d75ac97cb1cd725adac136d25ca687da4536154cdc2815f576e4da11c69"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d126361607b33c4eb7b36debc173bf25d7805847346dd4d99b5499e1fef52bc7"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4719bb05094d7d8563a450cf8738d2e1061420f79cfcc1fa7f0a44744c4d8f73"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5dd58946bce44b53b06d94aa95560d0b243eb2fe64227cba50017a8d8b3cd3e2"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22a86d9fff2009302c440b9d799ef2fe322416d2d58fc124b926aa89365ec482"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2aae8101919e8aa05ecfe6322b278f41ce2994c4a430303c4cd163fef746e04f"}, - {file = "regex-2023.12.25-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e692296c4cc2873967771345a876bcfc1c547e8dd695c6b89342488b0ea55cd8"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:263ef5cc10979837f243950637fffb06e8daed7f1ac1e39d5910fd29929e489a"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d6f7e255e5fa94642a0724e35406e6cb7001c09d476ab5fce002f652b36d0c39"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:88ad44e220e22b63b0f8f81f007e8abbb92874d8ced66f32571ef8beb0643b2b"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:3a17d3ede18f9cedcbe23d2daa8a2cd6f59fe2bf082c567e43083bba3fb00347"}, - {file = "regex-2023.12.25-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d15b274f9e15b1a0b7a45d2ac86d1f634d983ca40d6b886721626c47a400bf39"}, - {file = "regex-2023.12.25-cp37-cp37m-win32.whl", hash = "sha256:ed19b3a05ae0c97dd8f75a5d8f21f7723a8c33bbc555da6bbe1f96c470139d3c"}, - {file = "regex-2023.12.25-cp37-cp37m-win_amd64.whl", hash = "sha256:a6d1047952c0b8104a1d371f88f4ab62e6275567d4458c1e26e9627ad489b445"}, - {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b43523d7bc2abd757119dbfb38af91b5735eea45537ec6ec3a5ec3f9562a1c53"}, - {file = "regex-2023.12.25-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:efb2d82f33b2212898f1659fb1c2e9ac30493ac41e4d53123da374c3b5541e64"}, - {file = "regex-2023.12.25-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7fca9205b59c1a3d5031f7e64ed627a1074730a51c2a80e97653e3e9fa0d415"}, - {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086dd15e9435b393ae06f96ab69ab2d333f5d65cbe65ca5a3ef0ec9564dfe770"}, - {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e81469f7d01efed9b53740aedd26085f20d49da65f9c1f41e822a33992cb1590"}, - {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34e4af5b27232f68042aa40a91c3b9bb4da0eeb31b7632e0091afc4310afe6cb"}, - {file = "regex-2023.12.25-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9852b76ab558e45b20bf1893b59af64a28bd3820b0c2efc80e0a70a4a3ea51c1"}, - {file = "regex-2023.12.25-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff100b203092af77d1a5a7abe085b3506b7eaaf9abf65b73b7d6905b6cb76988"}, - {file = "regex-2023.12.25-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cc038b2d8b1470364b1888a98fd22d616fba2b6309c5b5f181ad4483e0017861"}, - {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:094ba386bb5c01e54e14434d4caabf6583334090865b23ef58e0424a6286d3dc"}, - {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5cd05d0f57846d8ba4b71d9c00f6f37d6b97d5e5ef8b3c3840426a475c8f70f4"}, - {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:9aa1a67bbf0f957bbe096375887b2505f5d8ae16bf04488e8b0f334c36e31360"}, - {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:98a2636994f943b871786c9e82bfe7883ecdaba2ef5df54e1450fa9869d1f756"}, - {file = "regex-2023.12.25-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37f8e93a81fc5e5bd8db7e10e62dc64261bcd88f8d7e6640aaebe9bc180d9ce2"}, - {file = "regex-2023.12.25-cp38-cp38-win32.whl", hash = "sha256:d78bd484930c1da2b9679290a41cdb25cc127d783768a0369d6b449e72f88beb"}, - {file = "regex-2023.12.25-cp38-cp38-win_amd64.whl", hash = "sha256:b521dcecebc5b978b447f0f69b5b7f3840eac454862270406a39837ffae4e697"}, - {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f7bc09bc9c29ebead055bcba136a67378f03d66bf359e87d0f7c759d6d4ffa31"}, - {file = "regex-2023.12.25-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e14b73607d6231f3cc4622809c196b540a6a44e903bcfad940779c80dffa7be7"}, - {file = "regex-2023.12.25-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9eda5f7a50141291beda3edd00abc2d4a5b16c29c92daf8d5bd76934150f3edc"}, - {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc6bb9aa69aacf0f6032c307da718f61a40cf970849e471254e0e91c56ffca95"}, - {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:298dc6354d414bc921581be85695d18912bea163a8b23cac9a2562bbcd5088b1"}, - {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2f4e475a80ecbd15896a976aa0b386c5525d0ed34d5c600b6d3ebac0a67c7ddf"}, - {file = "regex-2023.12.25-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531ac6cf22b53e0696f8e1d56ce2396311254eb806111ddd3922c9d937151dae"}, - {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22f3470f7524b6da61e2020672df2f3063676aff444db1daa283c2ea4ed259d6"}, - {file = "regex-2023.12.25-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:89723d2112697feaa320c9d351e5f5e7b841e83f8b143dba8e2d2b5f04e10923"}, - {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0ecf44ddf9171cd7566ef1768047f6e66975788258b1c6c6ca78098b95cf9a3d"}, - {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:905466ad1702ed4acfd67a902af50b8db1feeb9781436372261808df7a2a7bca"}, - {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:4558410b7a5607a645e9804a3e9dd509af12fb72b9825b13791a37cd417d73a5"}, - {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7e316026cc1095f2a3e8cc012822c99f413b702eaa2ca5408a513609488cb62f"}, - {file = "regex-2023.12.25-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3b1de218d5375cd6ac4b5493e0b9f3df2be331e86520f23382f216c137913d20"}, - {file = "regex-2023.12.25-cp39-cp39-win32.whl", hash = "sha256:11a963f8e25ab5c61348d090bf1b07f1953929c13bd2309a0662e9ff680763c9"}, - {file = "regex-2023.12.25-cp39-cp39-win_amd64.whl", hash = "sha256:e693e233ac92ba83a87024e1d32b5f9ab15ca55ddd916d878146f4e3406b5c91"}, - {file = "regex-2023.12.25.tar.gz", hash = "sha256:29171aa128da69afdf4bde412d5bedc335f2ca8fcfe4489038577d05f16181e5"}, -] - -[[package]] -name = "requests" -version = "2.31.0" -description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.7" -files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, -] - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" -idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<3" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)"] -use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] - -[[package]] -name = "rich" -version = "13.7.1" -description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -optional = false -python-versions = ">=3.7.0" -files = [ - {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, - {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, -] - -[package.dependencies] -markdown-it-py = ">=2.2.0" -pygments = ">=2.13.0,<3.0.0" - -[package.extras] -jupyter = ["ipywidgets (>=7.5.1,<9)"] - -[[package]] -name = "ruff" -version = "0.3.4" -description = "An extremely fast Python linter and code formatter, written in Rust." -optional = false -python-versions = ">=3.7" -files = [ - {file = "ruff-0.3.4-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:60c870a7d46efcbc8385d27ec07fe534ac32f3b251e4fc44b3cbfd9e09609ef4"}, - {file = "ruff-0.3.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6fc14fa742e1d8f24910e1fff0bd5e26d395b0e0e04cc1b15c7c5e5fe5b4af91"}, - {file = "ruff-0.3.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3ee7880f653cc03749a3bfea720cf2a192e4f884925b0cf7eecce82f0ce5854"}, - {file = "ruff-0.3.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf133dd744f2470b347f602452a88e70dadfbe0fcfb5fd46e093d55da65f82f7"}, - {file = "ruff-0.3.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f3860057590e810c7ffea75669bdc6927bfd91e29b4baa9258fd48b540a4365"}, - {file = "ruff-0.3.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:986f2377f7cf12efac1f515fc1a5b753c000ed1e0a6de96747cdf2da20a1b369"}, - {file = "ruff-0.3.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fd98e85869603e65f554fdc5cddf0712e352fe6e61d29d5a6fe087ec82b76c"}, - {file = "ruff-0.3.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64abeed785dad51801b423fa51840b1764b35d6c461ea8caef9cf9e5e5ab34d9"}, - {file = "ruff-0.3.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df52972138318bc7546d92348a1ee58449bc3f9eaf0db278906eb511889c4b50"}, - {file = "ruff-0.3.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:98e98300056445ba2cc27d0b325fd044dc17fcc38e4e4d2c7711585bd0a958ed"}, - {file = "ruff-0.3.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:519cf6a0ebed244dce1dc8aecd3dc99add7a2ee15bb68cf19588bb5bf58e0488"}, - {file = "ruff-0.3.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bb0acfb921030d00070539c038cd24bb1df73a2981e9f55942514af8b17be94e"}, - {file = "ruff-0.3.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cf187a7e7098233d0d0c71175375c5162f880126c4c716fa28a8ac418dcf3378"}, - {file = "ruff-0.3.4-py3-none-win32.whl", hash = "sha256:af27ac187c0a331e8ef91d84bf1c3c6a5dea97e912a7560ac0cef25c526a4102"}, - {file = "ruff-0.3.4-py3-none-win_amd64.whl", hash = "sha256:de0d5069b165e5a32b3c6ffbb81c350b1e3d3483347196ffdf86dc0ef9e37dd6"}, - {file = "ruff-0.3.4-py3-none-win_arm64.whl", hash = "sha256:6810563cc08ad0096b57c717bd78aeac888a1bfd38654d9113cb3dc4d3f74232"}, - {file = "ruff-0.3.4.tar.gz", hash = "sha256:f0f4484c6541a99862b693e13a151435a279b271cff20e37101116a21e2a1ad1"}, -] - -[[package]] -name = "setuptools" -version = "69.2.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false -python-versions = ">=3.8" -files = [ - {file = "setuptools-69.2.0-py3-none-any.whl", hash = "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c"}, - {file = "setuptools-69.2.0.tar.gz", hash = "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - -[[package]] -name = "shellingham" -version = "1.5.4" -description = "Tool to Detect Surrounding Shell" -optional = false -python-versions = ">=3.7" -files = [ - {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, - {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, -] - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -description = "Sniff out which async library your code is running under" -optional = false -python-versions = ">=3.7" -files = [ - {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, - {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, -] - -[[package]] -name = "sql-smith" -version = "1.1.1" -description = "sql-smith is an SQL query builder with zero dependencies and a fluent interface." -optional = false -python-versions = ">=3.10,<4.0" -files = [ - {file = "sql_smith-1.1.1-py3-none-any.whl", hash = "sha256:f092a1816ee7bfd740cd381a38c2d4524e101f580eec0cb8ec6882ee8f90bbed"}, - {file = "sql_smith-1.1.1.tar.gz", hash = "sha256:5622205e4f8f1815ddb0bd347a0bc6bece507d2fccaa948f867f407dd6cf9c3d"}, -] - -[[package]] -name = "starlette" -version = "0.36.3" -description = "The little ASGI library that shines." -optional = false -python-versions = ">=3.8" -files = [ - {file = "starlette-0.36.3-py3-none-any.whl", hash = "sha256:13d429aa93a61dc40bf503e8c801db1f1bca3dc706b10ef2434a36123568f044"}, - {file = "starlette-0.36.3.tar.gz", hash = "sha256:90a671733cfb35771d8cc605e0b679d23b992f8dcfad48cc60b38cb29aeb7080"}, -] - -[package.dependencies] -anyio = ">=3.4.0,<5" - -[package.extras] -full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] - -[[package]] -name = "termcolor" -version = "2.4.0" -description = "ANSI color formatting for output in terminal" -optional = false -python-versions = ">=3.8" -files = [ - {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, - {file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"}, -] - -[package.extras] -tests = ["pytest", "pytest-cov"] - -[[package]] -name = "text-unidecode" -version = "1.3" -description = "The most basic Text::Unidecode port" -optional = false -python-versions = "*" -files = [ - {file = "text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"}, - {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, -] - -[[package]] -name = "time-machine" -version = "2.14.1" -description = "Travel through time in your tests." -optional = false -python-versions = ">=3.8" -files = [ - {file = "time-machine-2.14.1.tar.gz", hash = "sha256:57dc7efc1dde4331902d1bdefd34e8ee890a5c28533157e3b14a429c86b39533"}, - {file = "time_machine-2.14.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:528d588d1e8ba83e45319a74acab4be0569eb141113fdf50368045d0a7d79cee"}, - {file = "time_machine-2.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06e913d570d7ee3e199e3316f10f10c8046287049141b0a101197712b4eac106"}, - {file = "time_machine-2.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddbbba954e9a409e7d66d60df2b6b8daeb897f8338f909a92d9d20e431ec70d1"}, - {file = "time_machine-2.14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72a153b085b4aee652d6b3bf9019ca897f1597ba9869b640b06f28736b267182"}, - {file = "time_machine-2.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b94274abe24b6a90d8a5c042167a9a7af2d3438b42ac8eb5ede50fbc73c08db"}, - {file = "time_machine-2.14.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:364353858708628655bf9fa4c2825febd679c729d9e1dd424ff86845828bac05"}, - {file = "time_machine-2.14.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b951b6f4b8a752ab8c441df422e21954a721a0a5276aa3814ce8cf7205aeb6da"}, - {file = "time_machine-2.14.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:be215eb63d74a3d580f7924bb4209c783fabcfb3253073f4dcb3424d57d0f518"}, - {file = "time_machine-2.14.1-cp310-cp310-win32.whl", hash = "sha256:0e120f95c17bf8e0c097fd8863a8eb24054f9b17d9b17c465694be50f8348a3a"}, - {file = "time_machine-2.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:fb467d6c9e9ab615c8cf22d751d34296dacf801be323a57adeb4ff345cf72473"}, - {file = "time_machine-2.14.1-cp310-cp310-win_arm64.whl", hash = "sha256:19db257117739b2dda1d57e149bb715a593313899b3902a7e6d752c5f1d22542"}, - {file = "time_machine-2.14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:442d42f1b0ef006f03a5a34905829a1d3ac569a5bcda64d29706e6dc60832f94"}, - {file = "time_machine-2.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0312b47f220e46f1bbfaded7fc1469882d9c2a27c6daf44e119aea7006b595cc"}, - {file = "time_machine-2.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a39dba3033d9c28347d2db16bcb16041bbf4e9032e2b70023686b6f95deac9d"}, - {file = "time_machine-2.14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e030d2051bb515251d7f6edd9bbcf79b2b47811e2c402aba9c126af713843d26"}, - {file = "time_machine-2.14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:993ab140eb5678d1ee7f1197f08e4499dc8ea883ad6b8858737de70d509ec5b5"}, - {file = "time_machine-2.14.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:90725f936ad8b123149bc82a46394dd7057e63157ee11ba878164053fa5bd8ad"}, - {file = "time_machine-2.14.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:59a02c3d3b3b29e2dc3a708e775c5d6b951b0024c4013fed883f0d2205305c9e"}, - {file = "time_machine-2.14.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4f00f67d532da82538c4dfbbddc587e70c82664f168c11e1c2915d0c85ec2fc8"}, - {file = "time_machine-2.14.1-cp311-cp311-win32.whl", hash = "sha256:27f735cba4c6352ad7bc53ce2d86b715379261a634e690b79fac329081e26fb6"}, - {file = "time_machine-2.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:ee68597bd3fa5ab94633c8a9d3ebd4032091559610e078381818a732910002bc"}, - {file = "time_machine-2.14.1-cp311-cp311-win_arm64.whl", hash = "sha256:6ced9de5eff1fb37efb12984ab7b63f31f0aeadeedec4be6d0404ec4fa91f2e7"}, - {file = "time_machine-2.14.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:30a4a18357fa6cf089eeefcb37e9549b42523aebb5933894770a8919e6c398e1"}, - {file = "time_machine-2.14.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d45bd60bea85869615b117667f10a821e3b0d3603c47bfd105b45d1f67156fc8"}, - {file = "time_machine-2.14.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:39de6d37a14ff8882d4f1cbd50c53268b54e1cf4ef9be2bfe590d10a51ccd314"}, - {file = "time_machine-2.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fd7d188b4f9d358c6bd477daf93b460d9b244a4c296ddd065945f2b6193c2bd"}, - {file = "time_machine-2.14.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99e6f013e67c4f74a9d8f57e34173b2047f2ad48f764e44c38f3ee5344a38c01"}, - {file = "time_machine-2.14.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a927d87501da8b053a27e80f5d0e1e58fbde4b50d70df2d3853ed67e89a731cf"}, - {file = "time_machine-2.14.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77a616561dd4c7c442e9eee8cbb915750496e9a5a7fca6bcb11a9860226d2d0"}, - {file = "time_machine-2.14.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e7fa70a6bdca40cc4a8386fd85bc1bae0a23ab11e49604ef853ab3ce92be127f"}, - {file = "time_machine-2.14.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d63ef00d389fa6d2c76c863af580b3e4a8f0ccc6a9aea8e64590588e37f13c00"}, - {file = "time_machine-2.14.1-cp312-cp312-win32.whl", hash = "sha256:6706eb06487354a5e219cacea709fb3ec44dec3842c6218237d5069fa5f1ad64"}, - {file = "time_machine-2.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:36aa4f17adcd73a6064bf4991a29126cac93521f0690805edb91db837c4e1453"}, - {file = "time_machine-2.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:edea570f3835a036e8860bb8d6eb8d08473c59313db86e36e3b207f796fd7b14"}, - {file = "time_machine-2.14.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:87e80408e6b6670e9ce33f94b1cc6b72b1a9b646f5e19f586908129871f74b40"}, - {file = "time_machine-2.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c69c0cb498c86ef843cd15964714e76465cc25d64464da57d5d1318f499de099"}, - {file = "time_machine-2.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc48d3934109b0bdbbdc5e9ce577213f7148a92fed378420ee13453503fe4db9"}, - {file = "time_machine-2.14.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7161cea2ff3244cc6075e365fab89000df70ead63a3da9d473983d580558d2de"}, - {file = "time_machine-2.14.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39fceeb131e6c07b386de042ce1016be771576e9516124b78e75cbab94ae5041"}, - {file = "time_machine-2.14.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:fe508a6c43fb72fa4f66b50b14684cf58d3db95fed617177ec197a7a90427bae"}, - {file = "time_machine-2.14.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5f3d5c21884aee10e13b00ef45fab893a43db9d59ec27271573528bd359b0ef5"}, - {file = "time_machine-2.14.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a75e24e59f58059bbbc50e7f97aa6d126bbc2f603a8a5cd1e884beffcf130d8f"}, - {file = "time_machine-2.14.1-cp38-cp38-win32.whl", hash = "sha256:b0f8ba70fbb71d7fbc6d6adb90bed72a83db15b3318c7af0060467539b2f1b63"}, - {file = "time_machine-2.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:15cf3623a4ba2bb4fce4529295570acd5f6c6b44bcbfd1b8d0756ce56c38fe82"}, - {file = "time_machine-2.14.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bb3a2518c52aa944989b541e5297b833388eb3fe72d91eb875b21fe771597b04"}, - {file = "time_machine-2.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:416d94eab7723c7d8a37fe6b3b1882046fdbf3c31b9abec3cac87cf35dbb8230"}, - {file = "time_machine-2.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adfbfa796dd96383400b44681eacc5ab06d3cbfad39c30878e5ead0bfdca808a"}, - {file = "time_machine-2.14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:31e6e9bff89b7c6e4cbc169ba1d00d6c107b3abc43173b2799352b6995cf7cb2"}, - {file = "time_machine-2.14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107caed387438d689180b692e8d84aa1ebe8918790df83dc5e2146e60e5e0859"}, - {file = "time_machine-2.14.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cab4abf4d1490a7da35db5a321ff8a4d4a2195f4832a792c75b626ffc4a5584c"}, - {file = "time_machine-2.14.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fd8645b820f7895fdafbc4412d1ce376956e36ad4fd05a43269aa06c3132afc3"}, - {file = "time_machine-2.14.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:dd26039a9ffea2d5ee1309f2ec9b656d4925371c65563822d52e4037a4186eca"}, - {file = "time_machine-2.14.1-cp39-cp39-win32.whl", hash = "sha256:5e19b19d20bfbff8c97949e06e150998cf9d0a676e1641fb90597e59a9d7d5e2"}, - {file = "time_machine-2.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:f5d371a5218318121a6b44c21438258b6408b8bfe7ccccb754cf8eb880505576"}, - {file = "time_machine-2.14.1-cp39-cp39-win_arm64.whl", hash = "sha256:2c774f4b603a36ca2611327c57aa8ce0d5042298da008238ee5234b31ce7b22c"}, -] - -[package.dependencies] -python-dateutil = "*" - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - -[[package]] -name = "typer" -version = "0.9.4" -description = "Typer, build great CLIs. Easy to code. Based on Python type hints." -optional = false -python-versions = ">=3.6" -files = [ - {file = "typer-0.9.4-py3-none-any.whl", hash = "sha256:aa6c4a4e2329d868b80ecbaf16f807f2b54e192209d7ac9dd42691d63f7a54eb"}, - {file = "typer-0.9.4.tar.gz", hash = "sha256:f714c2d90afae3a7929fcd72a3abb08df305e1ff61719381384211c4070af57f"}, -] - -[package.dependencies] -click = ">=7.1.1,<9.0.0" -colorama = {version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"all\""} -rich = {version = ">=10.11.0,<14.0.0", optional = true, markers = "extra == \"all\""} -shellingham = {version = ">=1.3.0,<2.0.0", optional = true, markers = "extra == \"all\""} -typing-extensions = ">=3.7.4.3" - -[package.extras] -all = ["colorama (>=0.4.3,<0.5.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] -dev = ["autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "pre-commit (>=2.17.0,<3.0.0)"] -doc = ["cairosvg (>=2.5.2,<3.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pillow (>=9.3.0,<10.0.0)"] -test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.971)", "pytest (>=4.4.0,<8.0.0)", "pytest-cov (>=2.10.0,<5.0.0)", "pytest-sugar (>=0.9.4,<0.10.0)", "pytest-xdist (>=1.32.0,<4.0.0)", "rich (>=10.11.0,<14.0.0)", "shellingham (>=1.3.0,<2.0.0)"] - -[[package]] -name = "typing-extensions" -version = "4.10.0" -description = "Backported and Experimental Type Hints for Python 3.8+" -optional = false -python-versions = ">=3.8" -files = [ - {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, - {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, -] - -[[package]] -name = "tzdata" -version = "2024.1" -description = "Provider of IANA time zone data" -optional = false -python-versions = ">=2" -files = [ - {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, - {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, -] - -[[package]] -name = "urllib3" -version = "2.2.1" -description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = false -python-versions = ">=3.8" -files = [ - {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, - {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, -] - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -h2 = ["h2 (>=4,<5)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] - -[[package]] -name = "uvicorn" -version = "0.27.1" -description = "The lightning-fast ASGI server." -optional = false -python-versions = ">=3.8" -files = [ - {file = "uvicorn-0.27.1-py3-none-any.whl", hash = "sha256:5c89da2f3895767472a35556e539fd59f7edbe9b1e9c0e1c99eebeadc61838e4"}, - {file = "uvicorn-0.27.1.tar.gz", hash = "sha256:3d9a267296243532db80c83a959a3400502165ade2c1338dea4e67915fd4745a"}, -] - -[package.dependencies] -click = ">=7.0" -colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} -h11 = ">=0.8" -httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standard\""} -python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} -pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} -uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} -watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} -websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} - -[package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] - -[[package]] -name = "uvloop" -version = "0.19.0" -description = "Fast implementation of asyncio event loop on top of libuv" -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e"}, - {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428"}, - {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8"}, - {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849"}, - {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957"}, - {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd"}, - {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef"}, - {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2"}, - {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1"}, - {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24"}, - {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533"}, - {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12"}, - {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650"}, - {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec"}, - {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc"}, - {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6"}, - {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593"}, - {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3"}, - {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:78ab247f0b5671cc887c31d33f9b3abfb88d2614b84e4303f1a63b46c046c8bd"}, - {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:472d61143059c84947aa8bb74eabbace30d577a03a1805b77933d6bd13ddebbd"}, - {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45bf4c24c19fb8a50902ae37c5de50da81de4922af65baf760f7c0c42e1088be"}, - {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271718e26b3e17906b28b67314c45d19106112067205119dddbd834c2b7ce797"}, - {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:34175c9fd2a4bc3adc1380e1261f60306344e3407c20a4d684fd5f3be010fa3d"}, - {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e27f100e1ff17f6feeb1f33968bc185bf8ce41ca557deee9d9bbbffeb72030b7"}, - {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13dfdf492af0aa0a0edf66807d2b465607d11c4fa48f4a1fd41cbea5b18e8e8b"}, - {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e3d4e85ac060e2342ff85e90d0c04157acb210b9ce508e784a944f852a40e67"}, - {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca4956c9ab567d87d59d49fa3704cf29e37109ad348f2d5223c9bf761a332e7"}, - {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f467a5fd23b4fc43ed86342641f3936a68ded707f4627622fa3f82a120e18256"}, - {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:492e2c32c2af3f971473bc22f086513cedfc66a130756145a931a90c3958cb17"}, - {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2df95fca285a9f5bfe730e51945ffe2fa71ccbfdde3b0da5772b4ee4f2e770d5"}, - {file = "uvloop-0.19.0.tar.gz", hash = "sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd"}, -] - -[package.extras] -docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] - -[[package]] -name = "virtualenv" -version = "20.25.1" -description = "Virtual Python Environment builder" -optional = false -python-versions = ">=3.7" -files = [ - {file = "virtualenv-20.25.1-py3-none-any.whl", hash = "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a"}, - {file = "virtualenv-20.25.1.tar.gz", hash = "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197"}, -] - -[package.dependencies] -distlib = ">=0.3.7,<1" -filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<5" - -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] - -[[package]] -name = "watchdog" -version = "4.0.0" -description = "Filesystem events monitoring" -optional = false -python-versions = ">=3.8" -files = [ - {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:39cb34b1f1afbf23e9562501673e7146777efe95da24fab5707b88f7fb11649b"}, - {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c522392acc5e962bcac3b22b9592493ffd06d1fc5d755954e6be9f4990de932b"}, - {file = "watchdog-4.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c47bdd680009b11c9ac382163e05ca43baf4127954c5f6d0250e7d772d2b80c"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8350d4055505412a426b6ad8c521bc7d367d1637a762c70fdd93a3a0d595990b"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c17d98799f32e3f55f181f19dd2021d762eb38fdd381b4a748b9f5a36738e935"}, - {file = "watchdog-4.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4986db5e8880b0e6b7cd52ba36255d4793bf5cdc95bd6264806c233173b1ec0b"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11e12fafb13372e18ca1bbf12d50f593e7280646687463dd47730fd4f4d5d257"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5369136a6474678e02426bd984466343924d1df8e2fd94a9b443cb7e3aa20d19"}, - {file = "watchdog-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76ad8484379695f3fe46228962017a7e1337e9acadafed67eb20aabb175df98b"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:45cc09cc4c3b43fb10b59ef4d07318d9a3ecdbff03abd2e36e77b6dd9f9a5c85"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eed82cdf79cd7f0232e2fdc1ad05b06a5e102a43e331f7d041e5f0e0a34a51c4"}, - {file = "watchdog-4.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba30a896166f0fee83183cec913298151b73164160d965af2e93a20bbd2ab605"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d18d7f18a47de6863cd480734613502904611730f8def45fc52a5d97503e5101"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2895bf0518361a9728773083908801a376743bcc37dfa252b801af8fd281b1ca"}, - {file = "watchdog-4.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87e9df830022488e235dd601478c15ad73a0389628588ba0b028cb74eb72fed8"}, - {file = "watchdog-4.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6e949a8a94186bced05b6508faa61b7adacc911115664ccb1923b9ad1f1ccf7b"}, - {file = "watchdog-4.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6a4db54edea37d1058b08947c789a2354ee02972ed5d1e0dca9b0b820f4c7f92"}, - {file = "watchdog-4.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d31481ccf4694a8416b681544c23bd271f5a123162ab603c7d7d2dd7dd901a07"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8fec441f5adcf81dd240a5fe78e3d83767999771630b5ddfc5867827a34fa3d3"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:6a9c71a0b02985b4b0b6d14b875a6c86ddea2fdbebd0c9a720a806a8bbffc69f"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:557ba04c816d23ce98a06e70af6abaa0485f6d94994ec78a42b05d1c03dcbd50"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0f9bd1fd919134d459d8abf954f63886745f4660ef66480b9d753a7c9d40927"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f9b2fdca47dc855516b2d66eef3c39f2672cbf7e7a42e7e67ad2cbfcd6ba107d"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:73c7a935e62033bd5e8f0da33a4dcb763da2361921a69a5a95aaf6c93aa03a87"}, - {file = "watchdog-4.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6a80d5cae8c265842c7419c560b9961561556c4361b297b4c431903f8c33b269"}, - {file = "watchdog-4.0.0-py3-none-win32.whl", hash = "sha256:8f9a542c979df62098ae9c58b19e03ad3df1c9d8c6895d96c0d51da17b243b1c"}, - {file = "watchdog-4.0.0-py3-none-win_amd64.whl", hash = "sha256:f970663fa4f7e80401a7b0cbeec00fa801bf0287d93d48368fc3e6fa32716245"}, - {file = "watchdog-4.0.0-py3-none-win_ia64.whl", hash = "sha256:9a03e16e55465177d416699331b0f3564138f1807ecc5f2de9d55d8f188d08c7"}, - {file = "watchdog-4.0.0.tar.gz", hash = "sha256:e3e7065cbdabe6183ab82199d7a4f6b3ba0a438c5a512a68559846ccb76a78ec"}, -] - -[package.extras] -watchmedo = ["PyYAML (>=3.10)"] - -[[package]] -name = "watchfiles" -version = "0.21.0" -description = "Simple, modern and high performance file watching and code reload in python." -optional = false -python-versions = ">=3.8" -files = [ - {file = "watchfiles-0.21.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:27b4035013f1ea49c6c0b42d983133b136637a527e48c132d368eb19bf1ac6aa"}, - {file = "watchfiles-0.21.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c81818595eff6e92535ff32825f31c116f867f64ff8cdf6562cd1d6b2e1e8f3e"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6c107ea3cf2bd07199d66f156e3ea756d1b84dfd43b542b2d870b77868c98c03"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d9ac347653ebd95839a7c607608703b20bc07e577e870d824fa4801bc1cb124"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5eb86c6acb498208e7663ca22dbe68ca2cf42ab5bf1c776670a50919a56e64ab"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f564bf68404144ea6b87a78a3f910cc8de216c6b12a4cf0b27718bf4ec38d303"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d0f32ebfaa9c6011f8454994f86108c2eb9c79b8b7de00b36d558cadcedaa3d"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6d45d9b699ecbac6c7bd8e0a2609767491540403610962968d258fd6405c17c"}, - {file = "watchfiles-0.21.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:aff06b2cac3ef4616e26ba17a9c250c1fe9dd8a5d907d0193f84c499b1b6e6a9"}, - {file = "watchfiles-0.21.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d9792dff410f266051025ecfaa927078b94cc7478954b06796a9756ccc7e14a9"}, - {file = "watchfiles-0.21.0-cp310-none-win32.whl", hash = "sha256:214cee7f9e09150d4fb42e24919a1e74d8c9b8a9306ed1474ecaddcd5479c293"}, - {file = "watchfiles-0.21.0-cp310-none-win_amd64.whl", hash = "sha256:1ad7247d79f9f55bb25ab1778fd47f32d70cf36053941f07de0b7c4e96b5d235"}, - {file = "watchfiles-0.21.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:668c265d90de8ae914f860d3eeb164534ba2e836811f91fecc7050416ee70aa7"}, - {file = "watchfiles-0.21.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a23092a992e61c3a6a70f350a56db7197242f3490da9c87b500f389b2d01eef"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e7941bbcfdded9c26b0bf720cb7e6fd803d95a55d2c14b4bd1f6a2772230c586"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11cd0c3100e2233e9c53106265da31d574355c288e15259c0d40a4405cbae317"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78f30cbe8b2ce770160d3c08cff01b2ae9306fe66ce899b73f0409dc1846c1b"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6674b00b9756b0af620aa2a3346b01f8e2a3dc729d25617e1b89cf6af4a54eb1"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd7ac678b92b29ba630d8c842d8ad6c555abda1b9ef044d6cc092dacbfc9719d"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c873345680c1b87f1e09e0eaf8cf6c891b9851d8b4d3645e7efe2ec20a20cc7"}, - {file = "watchfiles-0.21.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49f56e6ecc2503e7dbe233fa328b2be1a7797d31548e7a193237dcdf1ad0eee0"}, - {file = "watchfiles-0.21.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:02d91cbac553a3ad141db016e3350b03184deaafeba09b9d6439826ee594b365"}, - {file = "watchfiles-0.21.0-cp311-none-win32.whl", hash = "sha256:ebe684d7d26239e23d102a2bad2a358dedf18e462e8808778703427d1f584400"}, - {file = "watchfiles-0.21.0-cp311-none-win_amd64.whl", hash = "sha256:4566006aa44cb0d21b8ab53baf4b9c667a0ed23efe4aaad8c227bfba0bf15cbe"}, - {file = "watchfiles-0.21.0-cp311-none-win_arm64.whl", hash = "sha256:c550a56bf209a3d987d5a975cdf2063b3389a5d16caf29db4bdddeae49f22078"}, - {file = "watchfiles-0.21.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:51ddac60b96a42c15d24fbdc7a4bfcd02b5a29c047b7f8bf63d3f6f5a860949a"}, - {file = "watchfiles-0.21.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:511f0b034120cd1989932bf1e9081aa9fb00f1f949fbd2d9cab6264916ae89b1"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cfb92d49dbb95ec7a07511bc9efb0faff8fe24ef3805662b8d6808ba8409a71a"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f92944efc564867bbf841c823c8b71bb0be75e06b8ce45c084b46411475a915"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:642d66b75eda909fd1112d35c53816d59789a4b38c141a96d62f50a3ef9b3360"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d23bcd6c8eaa6324fe109d8cac01b41fe9a54b8c498af9ce464c1aeeb99903d6"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18d5b4da8cf3e41895b34e8c37d13c9ed294954907929aacd95153508d5d89d7"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b8d1eae0f65441963d805f766c7e9cd092f91e0c600c820c764a4ff71a0764c"}, - {file = "watchfiles-0.21.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1fd9a5205139f3c6bb60d11f6072e0552f0a20b712c85f43d42342d162be1235"}, - {file = "watchfiles-0.21.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a1e3014a625bcf107fbf38eece0e47fa0190e52e45dc6eee5a8265ddc6dc5ea7"}, - {file = "watchfiles-0.21.0-cp312-none-win32.whl", hash = "sha256:9d09869f2c5a6f2d9df50ce3064b3391d3ecb6dced708ad64467b9e4f2c9bef3"}, - {file = "watchfiles-0.21.0-cp312-none-win_amd64.whl", hash = "sha256:18722b50783b5e30a18a8a5db3006bab146d2b705c92eb9a94f78c72beb94094"}, - {file = "watchfiles-0.21.0-cp312-none-win_arm64.whl", hash = "sha256:a3b9bec9579a15fb3ca2d9878deae789df72f2b0fdaf90ad49ee389cad5edab6"}, - {file = "watchfiles-0.21.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:4ea10a29aa5de67de02256a28d1bf53d21322295cb00bd2d57fcd19b850ebd99"}, - {file = "watchfiles-0.21.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:40bca549fdc929b470dd1dbfcb47b3295cb46a6d2c90e50588b0a1b3bd98f429"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9b37a7ba223b2f26122c148bb8d09a9ff312afca998c48c725ff5a0a632145f7"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec8c8900dc5c83650a63dd48c4d1d245343f904c4b64b48798c67a3767d7e165"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ad3fe0a3567c2f0f629d800409cd528cb6251da12e81a1f765e5c5345fd0137"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d353c4cfda586db2a176ce42c88f2fc31ec25e50212650c89fdd0f560ee507b"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:83a696da8922314ff2aec02987eefb03784f473281d740bf9170181829133765"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a03651352fc20975ee2a707cd2d74a386cd303cc688f407296064ad1e6d1562"}, - {file = "watchfiles-0.21.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3ad692bc7792be8c32918c699638b660c0de078a6cbe464c46e1340dadb94c19"}, - {file = "watchfiles-0.21.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06247538e8253975bdb328e7683f8515ff5ff041f43be6c40bff62d989b7d0b0"}, - {file = "watchfiles-0.21.0-cp38-none-win32.whl", hash = "sha256:9a0aa47f94ea9a0b39dd30850b0adf2e1cd32a8b4f9c7aa443d852aacf9ca214"}, - {file = "watchfiles-0.21.0-cp38-none-win_amd64.whl", hash = "sha256:8d5f400326840934e3507701f9f7269247f7c026d1b6cfd49477d2be0933cfca"}, - {file = "watchfiles-0.21.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:7f762a1a85a12cc3484f77eee7be87b10f8c50b0b787bb02f4e357403cad0c0e"}, - {file = "watchfiles-0.21.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6e9be3ef84e2bb9710f3f777accce25556f4a71e15d2b73223788d528fcc2052"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4c48a10d17571d1275701e14a601e36959ffada3add8cdbc9e5061a6e3579a5d"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c889025f59884423428c261f212e04d438de865beda0b1e1babab85ef4c0f01"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:66fac0c238ab9a2e72d026b5fb91cb902c146202bbd29a9a1a44e8db7b710b6f"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4a21f71885aa2744719459951819e7bf5a906a6448a6b2bbce8e9cc9f2c8128"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c9198c989f47898b2c22201756f73249de3748e0fc9de44adaf54a8b259cc0c"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8f57c4461cd24fda22493109c45b3980863c58a25b8bec885ca8bea6b8d4b28"}, - {file = "watchfiles-0.21.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:853853cbf7bf9408b404754b92512ebe3e3a83587503d766d23e6bf83d092ee6"}, - {file = "watchfiles-0.21.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d5b1dc0e708fad9f92c296ab2f948af403bf201db8fb2eb4c8179db143732e49"}, - {file = "watchfiles-0.21.0-cp39-none-win32.whl", hash = "sha256:59137c0c6826bd56c710d1d2bda81553b5e6b7c84d5a676747d80caf0409ad94"}, - {file = "watchfiles-0.21.0-cp39-none-win_amd64.whl", hash = "sha256:6cb8fdc044909e2078c248986f2fc76f911f72b51ea4a4fbbf472e01d14faa58"}, - {file = "watchfiles-0.21.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab03a90b305d2588e8352168e8c5a1520b721d2d367f31e9332c4235b30b8994"}, - {file = "watchfiles-0.21.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:927c589500f9f41e370b0125c12ac9e7d3a2fd166b89e9ee2828b3dda20bfe6f"}, - {file = "watchfiles-0.21.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bd467213195e76f838caf2c28cd65e58302d0254e636e7c0fca81efa4a2e62c"}, - {file = "watchfiles-0.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02b73130687bc3f6bb79d8a170959042eb56eb3a42df3671c79b428cd73f17cc"}, - {file = "watchfiles-0.21.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:08dca260e85ffae975448e344834d765983237ad6dc308231aa16e7933db763e"}, - {file = "watchfiles-0.21.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:3ccceb50c611c433145502735e0370877cced72a6c70fd2410238bcbc7fe51d8"}, - {file = "watchfiles-0.21.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57d430f5fb63fea141ab71ca9c064e80de3a20b427ca2febcbfcef70ff0ce895"}, - {file = "watchfiles-0.21.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dd5fad9b9c0dd89904bbdea978ce89a2b692a7ee8a0ce19b940e538c88a809c"}, - {file = "watchfiles-0.21.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:be6dd5d52b73018b21adc1c5d28ac0c68184a64769052dfeb0c5d9998e7f56a2"}, - {file = "watchfiles-0.21.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b3cab0e06143768499384a8a5efb9c4dc53e19382952859e4802f294214f36ec"}, - {file = "watchfiles-0.21.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c6ed10c2497e5fedadf61e465b3ca12a19f96004c15dcffe4bd442ebadc2d85"}, - {file = "watchfiles-0.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43babacef21c519bc6631c5fce2a61eccdfc011b4bcb9047255e9620732c8097"}, - {file = "watchfiles-0.21.0.tar.gz", hash = "sha256:c76c635fabf542bb78524905718c39f736a98e5ab25b23ec6d4abede1a85a6a3"}, -] - -[package.dependencies] -anyio = ">=3.0.0" - -[[package]] -name = "websockets" -version = "12.0" -description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -optional = false -python-versions = ">=3.8" -files = [ - {file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"}, - {file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"}, - {file = "websockets-12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603"}, - {file = "websockets-12.0-cp310-cp310-win32.whl", hash = "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f"}, - {file = "websockets-12.0-cp310-cp310-win_amd64.whl", hash = "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf"}, - {file = "websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4"}, - {file = "websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f"}, - {file = "websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53"}, - {file = "websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402"}, - {file = "websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b"}, - {file = "websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df"}, - {file = "websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc"}, - {file = "websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113"}, - {file = "websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d"}, - {file = "websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f"}, - {file = "websockets-12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5f6ffe2c6598f7f7207eef9a1228b6f5c818f9f4d53ee920aacd35cec8110438"}, - {file = "websockets-12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9edf3fc590cc2ec20dc9d7a45108b5bbaf21c0d89f9fd3fd1685e223771dc0b2"}, - {file = "websockets-12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8572132c7be52632201a35f5e08348137f658e5ffd21f51f94572ca6c05ea81d"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604428d1b87edbf02b233e2c207d7d528460fa978f9e391bd8aaf9c8311de137"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a9d160fd080c6285e202327aba140fc9a0d910b09e423afff4ae5cbbf1c7205"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b4aafed34653e465eb77b7c93ef058516cb5acf3eb21e42f33928616172def"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b2ee7288b85959797970114deae81ab41b731f19ebcd3bd499ae9ca0e3f1d2c8"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7fa3d25e81bfe6a89718e9791128398a50dec6d57faf23770787ff441d851967"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a571f035a47212288e3b3519944f6bf4ac7bc7553243e41eac50dd48552b6df7"}, - {file = "websockets-12.0-cp38-cp38-win32.whl", hash = "sha256:3c6cc1360c10c17463aadd29dd3af332d4a1adaa8796f6b0e9f9df1fdb0bad62"}, - {file = "websockets-12.0-cp38-cp38-win_amd64.whl", hash = "sha256:1bf386089178ea69d720f8db6199a0504a406209a0fc23e603b27b300fdd6892"}, - {file = "websockets-12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ab3d732ad50a4fbd04a4490ef08acd0517b6ae6b77eb967251f4c263011a990d"}, - {file = "websockets-12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1d9697f3337a89691e3bd8dc56dea45a6f6d975f92e7d5f773bc715c15dde28"}, - {file = "websockets-12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1df2fbd2c8a98d38a66f5238484405b8d1d16f929bb7a33ed73e4801222a6f53"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23509452b3bc38e3a057382c2e941d5ac2e01e251acce7adc74011d7d8de434c"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e5fc14ec6ea568200ea4ef46545073da81900a2b67b3e666f04adf53ad452ec"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46e71dbbd12850224243f5d2aeec90f0aaa0f2dde5aeeb8fc8df21e04d99eff9"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b81f90dcc6c85a9b7f29873beb56c94c85d6f0dac2ea8b60d995bd18bf3e2aae"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a02413bc474feda2849c59ed2dfb2cddb4cd3d2f03a2fedec51d6e959d9b608b"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bbe6013f9f791944ed31ca08b077e26249309639313fff132bfbf3ba105673b9"}, - {file = "websockets-12.0-cp39-cp39-win32.whl", hash = "sha256:cbe83a6bbdf207ff0541de01e11904827540aa069293696dd528a6640bd6a5f6"}, - {file = "websockets-12.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc4e7fa5414512b481a2483775a8e8be7803a35b30ca805afa4998a84f9fd9e8"}, - {file = "websockets-12.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b"}, - {file = "websockets-12.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30"}, - {file = "websockets-12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2"}, - {file = "websockets-12.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468"}, - {file = "websockets-12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611"}, - {file = "websockets-12.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370"}, - {file = "websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e"}, - {file = "websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b"}, -] - -[[package]] -name = "win32-setctime" -version = "1.1.0" -description = "A small Python utility to set file creation time on Windows" -optional = false -python-versions = ">=3.5" -files = [ - {file = "win32_setctime-1.1.0-py3-none-any.whl", hash = "sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"}, - {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, -] - -[package.extras] -dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] - -[[package]] -name = "yarl" -version = "1.9.4" -description = "Yet another URL library" -optional = false -python-versions = ">=3.7" -files = [ - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"}, - {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"}, - {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"}, - {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"}, - {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"}, - {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"}, - {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"}, - {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"}, - {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"}, - {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"}, - {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"}, - {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"}, - {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"}, - {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"}, - {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"}, - {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"}, - {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"}, - {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"}, - {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"}, - {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"}, - {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"}, - {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"}, - {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"}, - {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"}, - {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"}, - {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"}, - {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"}, - {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"}, - {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"}, - {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"}, - {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"}, - {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"}, - {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"}, -] - -[package.dependencies] -idna = ">=2.0" -multidict = ">=4.0" - -[metadata] -lock-version = "2.0" -python-versions = "^3.12" -content-hash = "0ed7f7d661cf7de2e3d5718340ecfbfc9226a7dd80d1cfb00d4d99c8377d9f1b" diff --git a/backend/src/tests/api/conftest.py b/backend/src/tests/api/conftest.py index 0ff62d7e4..6322c1bec 100644 --- a/backend/src/tests/api/conftest.py +++ b/backend/src/tests/api/conftest.py @@ -1,8 +1,10 @@ """Module that defines fixtures for the api tests.""" + import pytest +from fastapi import FastAPI from fastapi.testclient import TestClient -from kwai.api.app import create_app +from kwai.api.app import create_api from kwai.core.settings import get_settings from kwai.modules.identity.users.user_account import UserAccountEntity @@ -10,7 +12,8 @@ @pytest.fixture(scope="module") def client() -> TestClient: """Get an HTTP client.""" - app = create_app(get_settings()) + app = FastAPI(title="kwai API -- TEST") + app.mount("/api", create_api(get_settings())) return TestClient(app) diff --git a/backend/src/tests/api/v1/auth/endpoints/test_user_invitations.py b/backend/src/tests/api/v1/auth/endpoints/test_user_invitations.py index 471543ed7..104744520 100644 --- a/backend/src/tests/api/v1/auth/endpoints/test_user_invitations.py +++ b/backend/src/tests/api/v1/auth/endpoints/test_user_invitations.py @@ -1,4 +1,5 @@ """Test the endpoint users.""" + import json import pytest @@ -45,7 +46,7 @@ def test_create_user_invitation(secure_client: TestClient, invitation_data: list response = secure_client.post( "api/v1/auth/users/invitations", content=json.dumps(data) ) - assert response.status_code == status.HTTP_200_OK, response.content + assert response.status_code == status.HTTP_201_CREATED, response.content invitation_data.append(response.json()["data"]["id"]) diff --git a/backend/src/tests/api/v1/club/schemas/conftest.py b/backend/src/tests/api/v1/club/schemas/conftest.py index 2df39e996..4f75e52eb 100644 --- a/backend/src/tests/api/v1/club/schemas/conftest.py +++ b/backend/src/tests/api/v1/club/schemas/conftest.py @@ -7,30 +7,10 @@ from kwai.core.domain.value_objects.date import Date from kwai.core.domain.value_objects.email_address import EmailAddress from kwai.core.domain.value_objects.name import Name -from kwai.modules.club.members.contact import ContactEntity, ContactIdentifier -from kwai.modules.club.members.country import CountryEntity, CountryIdentifier -from kwai.modules.club.members.person import PersonEntity, PersonIdentifier -from kwai.modules.club.members.value_objects import Address, Birthdate, Gender - - -@pytest.fixture -def country() -> CountryEntity: - """A fixture for a country.""" - return CountryEntity( - id_=CountryIdentifier(1), iso_2="JP", iso_3="JPN", name="Japan" - ) - - -@pytest.fixture -def expected_country_json() -> dict[str, Any]: - """A fixture for a JSON:API resource of a country.""" - return { - "data": { - "id": "1", - "type": "countries", - "attributes": {"iso_2": "JP", "iso_3": "JPN", "name": "Japan"}, - } - } +from kwai.modules.club.domain.contact import ContactEntity, ContactIdentifier +from kwai.modules.club.domain.country import CountryEntity +from kwai.modules.club.domain.person import PersonEntity, PersonIdentifier +from kwai.modules.club.domain.value_objects import Address, Birthdate, Gender @pytest.fixture diff --git a/backend/src/tests/api/v1/club/schemas/test_contact.py b/backend/src/tests/api/v1/club/schemas/test_contact.py index c0f809337..f995d6182 100644 --- a/backend/src/tests/api/v1/club/schemas/test_contact.py +++ b/backend/src/tests/api/v1/club/schemas/test_contact.py @@ -6,7 +6,7 @@ from deepdiff import DeepDiff from kwai.api.v1.club.schemas.contact import ContactDocument -from kwai.modules.club.members.contact import ContactEntity +from kwai.modules.club.domain.contact import ContactEntity def test_create_contact_document( diff --git a/backend/src/tests/api/v1/club/schemas/test_member.py b/backend/src/tests/api/v1/club/schemas/test_member.py index a76d6b58c..c4fda38b5 100644 --- a/backend/src/tests/api/v1/club/schemas/test_member.py +++ b/backend/src/tests/api/v1/club/schemas/test_member.py @@ -8,9 +8,9 @@ from kwai.api.v1.club.schemas.member import MemberDocument from kwai.core.domain.value_objects.date import Date -from kwai.modules.club.members.member import MemberEntity, MemberIdentifier -from kwai.modules.club.members.person import PersonEntity -from kwai.modules.club.members.value_objects import License +from kwai.modules.club.domain.member import MemberEntity, MemberIdentifier +from kwai.modules.club.domain.person import PersonEntity +from kwai.modules.club.domain.value_objects import License @pytest.fixture diff --git a/backend/src/tests/api/v1/club/schemas/test_person.py b/backend/src/tests/api/v1/club/schemas/test_person.py index d27b61684..41d10e737 100644 --- a/backend/src/tests/api/v1/club/schemas/test_person.py +++ b/backend/src/tests/api/v1/club/schemas/test_person.py @@ -6,7 +6,7 @@ from deepdiff import DeepDiff from kwai.api.v1.club.schemas.person import PersonDocument -from kwai.modules.club.members.person import PersonEntity +from kwai.modules.club.domain.person import PersonEntity def test_create_person_document( diff --git a/backend/src/tests/api/v1/conftest.py b/backend/src/tests/api/v1/conftest.py new file mode 100644 index 000000000..0f12ef5bc --- /dev/null +++ b/backend/src/tests/api/v1/conftest.py @@ -0,0 +1,27 @@ +"""Module for defining reusable fixtures.""" + +from typing import Any + +import pytest + +from kwai.modules.club.domain.country import CountryEntity, CountryIdentifier + + +@pytest.fixture +def country() -> CountryEntity: + """A fixture for a country.""" + return CountryEntity( + id_=CountryIdentifier(1), iso_2="JP", iso_3="JPN", name="Japan" + ) + + +@pytest.fixture +def expected_country_json() -> dict[str, Any]: + """A fixture for a JSON:API resource of a country.""" + return { + "data": { + "id": "1", + "type": "countries", + "attributes": {"iso_2": "JP", "iso_3": "JPN", "name": "Japan"}, + } + } diff --git a/backend/src/tests/api/v1/teams/__init__.py b/backend/src/tests/api/v1/teams/__init__.py new file mode 100644 index 000000000..2a4d512cf --- /dev/null +++ b/backend/src/tests/api/v1/teams/__init__.py @@ -0,0 +1 @@ +"""Package for testing the teams API.""" diff --git a/backend/src/tests/api/v1/teams/conftest.py b/backend/src/tests/api/v1/teams/conftest.py new file mode 100644 index 000000000..6a1ff2779 --- /dev/null +++ b/backend/src/tests/api/v1/teams/conftest.py @@ -0,0 +1,8 @@ +"""Module for defining common fixtures for testing the teams endpoints.""" + +from tests.fixtures.teams.teams import * # noqa +from tests.fixtures.teams.team_members import * # noqa +from tests.fixtures.club.countries import * # noqa +from tests.fixtures.club.contacts import * # noqa +from tests.fixtures.club.persons import * # noqa +from tests.fixtures.club.members import * # noqa diff --git a/backend/src/tests/api/v1/teams/test_api.py b/backend/src/tests/api/v1/teams/test_api.py new file mode 100644 index 000000000..639aa0211 --- /dev/null +++ b/backend/src/tests/api/v1/teams/test_api.py @@ -0,0 +1,120 @@ +"""Module for testing the teams API.""" + +import pytest +from fastapi import status +from fastapi.testclient import TestClient + +pytestmark = pytest.mark.api + + +async def test_get_team(client: TestClient, make_team_in_db): + """Test /api/v1/teams endpoint for getting a team.""" + team = await make_team_in_db() + response = client.get(f"/api/v1/teams/{team.id}") + assert response.status_code == status.HTTP_200_OK + + +async def test_get_teams(client: TestClient, make_team_in_db): + """Test /api/v1/teams endpoint for getting all teams.""" + await make_team_in_db() + response = client.get("/api/v1/teams") + assert response.status_code == status.HTTP_200_OK + + +async def test_delete_team(secure_client: TestClient, make_team_in_db): + """Test /api/v1/teams endpoint for deleting a team.""" + team = await make_team_in_db() + response = secure_client.delete(f"/api/v1/teams/{team.id}") + assert response.status_code == status.HTTP_200_OK + + +async def test_create_team(secure_client: TestClient, make_team): + """Test /api/v1/teams endpoint for creating a team.""" + team = make_team() + payload = { + "data": { + "type": "teams", + "attributes": { + "name": team.name, + "active": team.is_active, + "remark": team.remark, + }, + } + } + response = secure_client.post("/api/v1/teams", json=payload) + assert response.status_code == status.HTTP_201_CREATED + + +async def test_update_team(secure_client: TestClient, make_team_in_db): + """Test /api/v1/teams endpoint for updating a team.""" + team = await make_team_in_db() + payload = { + "data": { + "id": str(team.id), + "type": "teams", + "attributes": { + "name": team.name, + "active": team.is_active, + "remark": "This is a test", + }, + } + } + response = secure_client.patch(f"/api/v1/teams/{team.id}", json=payload) + assert response.status_code == status.HTTP_200_OK + assert ( + response.json()["data"]["attributes"]["remark"] == "This is a test" + ), "The team should be updated." + + +async def test_get_members( + secure_client: TestClient, make_team_in_db, make_member_in_db +): + """Test /api/v1/teams/members endpoint for getting members.""" + team = await make_team_in_db() + await make_member_in_db() + response = secure_client.get(f"/api/v1/teams/members?filter[team]=noteq:{team.id}") + assert response.status_code == status.HTTP_200_OK + + +async def test_get_team_members( + secure_client: TestClient, make_team_in_db, make_team_member_in_db +): + """Test /api/v1/teams//members endpoint for getting a team's members.""" + team = await make_team_in_db() + await make_team_member_in_db(team=team) + response = secure_client.get(f"/api/v1/teams/{team.id}/members") + assert response.status_code == status.HTTP_200_OK + + +async def test_create_team_member( + secure_client: TestClient, make_team_in_db, make_member_in_db +): + """Test /api/v1/teams//members endpoint for creating a team's member.""" + team = await make_team_in_db() + member = await make_member_in_db() + payload = { + "data": { + "type": "team_members", + "id": str(member.uuid), + "attributes": { + "active": True, + "first_name": member.person.name.first_name, + "last_name": member.person.name.last_name, + "license_number": member.license.number, + "license_end_date": str(member.license.end_date), + "gender": member.person.gender.value, + "birthdate": str(member.person.birthdate), + "active_in_club": True, + }, + "relationships": { + "nationality": { + "data": { + "type": "countries", + "id": str(member.person.nationality.id), + } + } + }, + } + } + response = secure_client.post(f"/api/v1/teams/{team.id}/members", json=payload) + assert response.status_code == status.HTTP_201_CREATED, response.json() diff --git a/backend/src/tests/api/v1/teams/test_schemas.py b/backend/src/tests/api/v1/teams/test_schemas.py new file mode 100644 index 000000000..13ad2d69d --- /dev/null +++ b/backend/src/tests/api/v1/teams/test_schemas.py @@ -0,0 +1,137 @@ +"""Module for testing teams schemas.""" + +import json +from typing import Any + +import pytest +from deepdiff import DeepDiff + +from kwai.api.v1.teams.schemas import TeamDocument, TeamMemberDocument +from kwai.core.domain.value_objects.date import Date +from kwai.core.domain.value_objects.name import Name +from kwai.core.domain.value_objects.traceable_time import TraceableTime +from kwai.core.domain.value_objects.unique_id import UniqueId +from kwai.modules.club.domain.value_objects import Birthdate, Gender, License +from kwai.modules.teams.domain.team import TeamEntity, TeamIdentifier +from kwai.modules.teams.domain.team_member import ( + MemberEntity, + MemberIdentifier, + TeamMember, +) +from tests.fixtures.club.countries import * # noqa + + +@pytest.fixture +def team_member(country_japan) -> TeamMember: + """A fixture for a team member.""" + return TeamMember( + active=True, + member=MemberEntity( + id_=MemberIdentifier(1), + name=Name(first_name="Jigoro", last_name="Kano"), + uuid=UniqueId.generate(), + license=License(number="1234", end_date=Date.today().add(years=1)), + birthdate=Birthdate(Date.create(year=1860, month=10, day=28)), + gender=Gender.MALE, + nationality=country_japan, + active_in_club=True, + ), + traceable_time=TraceableTime(), + ) + + +@pytest.fixture +def expected_team_member_json(team_member: TeamMember) -> dict[str, Any]: + """A fixture for a JSON:API resource of a team member.""" + return { + "data": { + "id": str(team_member.member.uuid), + "type": "team_members", + "meta": { + "created_at": str(team_member.traceable_time.created_at), + "updated_at": str(team_member.traceable_time.updated_at), + }, + "attributes": { + "active": True, + "first_name": "Jigoro", + "last_name": "Kano", + "gender": team_member.member.gender.value, + "birthdate": str(team_member.member.birthdate), + "license_number": team_member.member.license.number, + "license_end_date": str(team_member.member.license.end_date), + "active_in_club": True, + }, + "relationships": { + "nationality": { + "data": { + "id": str(team_member.member.nationality.id), + "type": "countries", + } + }, + "team": None, + }, + }, + "included": [ + { + "id": str(team_member.member.nationality.id), + "type": "countries", + "attributes": {"iso_2": "JP", "iso_3": "JPN", "name": "Japan"}, + } + ], + } + + +def test_create_team_member_document( + team_member: TeamMember, expected_team_member_json: dict[str, Any] +): + """Test the creation of a JSON:API document for a team member resource.""" + team_member_document = TeamMemberDocument.create(team_member) + json_resource = json.loads(team_member_document.json()) + + diff = DeepDiff(json_resource, expected_team_member_json, ignore_order=True) + assert not diff, f"JSON structure is not expected:{diff}" + + +@pytest.fixture +def team(team_member: TeamMember) -> TeamEntity: + """A fixture for a team entity.""" + return TeamEntity( + id_=TeamIdentifier(1), + name="U11", + members={team_member.member.uuid: team_member}, + ) + + +@pytest.fixture +def expected_team_json(team: TeamEntity, expected_team_member_json) -> dict[str, Any]: + """A fixture for a JSON:API resource of a team.""" + return { + "data": { + "id": "1", + "type": "teams", + "attributes": {"name": "U11", "remark": "", "active": True}, + "relationships": { + "team_members": { + "data": [ + { + "id": expected_team_member_json["data"]["id"], + "type": expected_team_member_json["data"]["type"], + } + ] + } + }, + }, + "included": [ + expected_team_member_json["data"], + *expected_team_member_json["included"], + ], + } + + +def test_create_team_document(team: TeamEntity, expected_team_json: dict[str, Any]): + """Test the creation of a JSON:API document for a team entity.""" + team_document = TeamDocument.create(team) + json_resource = json.loads(team_document.json()) + + diff = DeepDiff(json_resource, expected_team_json, ignore_order=True) + assert not diff, f"JSON structure is not expected:{diff}" diff --git a/backend/src/tests/api/v1/club/schemas/test_country.py b/backend/src/tests/api/v1/test_schemas.py similarity index 73% rename from backend/src/tests/api/v1/club/schemas/test_country.py rename to backend/src/tests/api/v1/test_schemas.py index b7dbcbffd..2bfb21f37 100644 --- a/backend/src/tests/api/v1/club/schemas/test_country.py +++ b/backend/src/tests/api/v1/test_schemas.py @@ -1,12 +1,12 @@ -"""Module for testing the country JSON:API resource.""" +"""Module for testing the common JSON:API schemas.""" import json from typing import Any from deepdiff import DeepDiff -from kwai.api.v1.club.schemas.country import CountryDocument -from kwai.modules.club.members.country import CountryEntity +from kwai.api.v1.schemas import CountryDocument +from kwai.modules.club.domain.country import CountryEntity def test_create_country_document( diff --git a/backend/src/tests/conftest.py b/backend/src/tests/conftest.py index 52c27b760..9a8a69057 100644 --- a/backend/src/tests/conftest.py +++ b/backend/src/tests/conftest.py @@ -1,4 +1,5 @@ """Module for sharing fixtures in this module.""" + import asyncio from typing import AsyncIterator, Iterator diff --git a/backend/src/tests/core/test_json_api.py b/backend/src/tests/core/test_json_api.py index 013b5b1c4..5db6f37ff 100644 --- a/backend/src/tests/core/test_json_api.py +++ b/backend/src/tests/core/test_json_api.py @@ -1,4 +1,5 @@ """Module for testing the JSON:API models.""" + from types import NoneType from typing import Literal @@ -6,7 +7,7 @@ from pydantic import BaseModel from rich import json -from kwai.core.json_api import Document, ResourceData, ResourceIdentifier +from kwai.core.json_api import Document, Error, ResourceData, ResourceIdentifier class JudokaResourceIdentifier(ResourceIdentifier): @@ -72,3 +73,19 @@ def test_dump_json(judoka_resource: JudokaResource): assert ( json_doc["data"]["attributes"]["name"] == "Jigoro Kano" ), "The judoka should have a name." + + +def test_error(): + """Test the error of a JSON:API document.""" + json_doc = JudokaDocument( + data=[], + errors=[ + Error( + title="No judoka selected", + detail="There is no judoka selected for this tournament", + ) + ], + ) + json_doc = json.loads(json_doc.model_dump_json()) + assert "errors" in json_doc, "There should be a 'errors' in the document." + assert json_doc["errors"][0]["title"] == "No judoka selected" diff --git a/backend/src/tests/fixtures/club/coaches.py b/backend/src/tests/fixtures/club/coaches.py new file mode 100644 index 000000000..b99be4610 --- /dev/null +++ b/backend/src/tests/fixtures/club/coaches.py @@ -0,0 +1,52 @@ +"""Module for defining fixtures for coaches.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.core.db.uow import UnitOfWork +from kwai.modules.club.domain.coach import CoachEntity +from kwai.modules.club.domain.member import MemberEntity +from kwai.modules.club.repositories.coach_db_repository import CoachDbRepository + + +@pytest.fixture +def make_coach(make_member): + """A factory fixture for a coach.""" + + def _make_coach( + member: MemberEntity | None = None, + active: bool = True, + ) -> CoachEntity: + member = member or make_member() + return CoachEntity(member=member or make_member(), active=active) + + return _make_coach + + +@pytest.fixture +def make_coach_in_db( + request, event_loop, database: Database, make_coach, make_member_in_db +): + """A factory fixture for a coach in a database.""" + + async def _make_coach_in_db( + coach: CoachEntity | None = None, member: MemberEntity | None = None + ): + member = member or await make_member_in_db() + coach = coach or make_coach(member=member) + repo = CoachDbRepository(database) + async with UnitOfWork(database): + coach = await repo.create(coach) + + def cleanup(): + async def acleanup(): + async with UnitOfWork(database): + await repo.delete(coach) + + event_loop.run_until_complete(acleanup()) + + request.addfinalizer(cleanup) + + return coach + + return _make_coach_in_db diff --git a/backend/src/tests/fixtures/club/contacts.py b/backend/src/tests/fixtures/club/contacts.py index 05f6e76e2..d94601f8d 100644 --- a/backend/src/tests/fixtures/club/contacts.py +++ b/backend/src/tests/fixtures/club/contacts.py @@ -1,40 +1,18 @@ """Module for defining fixtures for contacts.""" -from typing import ( - Awaitable, - Callable, - NotRequired, - TypeAlias, - TypedDict, - Unpack, -) - import pytest from kwai.core.db.database import Database from kwai.core.db.uow import UnitOfWork from kwai.core.domain.value_objects.email_address import EmailAddress -from kwai.modules.club.members.contact import ContactEntity -from kwai.modules.club.members.contact_db_repository import ContactDbRepository -from kwai.modules.club.members.country import CountryEntity -from kwai.modules.club.members.value_objects import Address - - -class AddressType(TypedDict): - """Keyword arguments for the Address fixture factory method.""" - - address: NotRequired[str] - postal_code: NotRequired[str] - city: NotRequired[str] - county: NotRequired[str] - country: NotRequired[CountryEntity] - - -AddressFixtureFactory: TypeAlias = Callable[[Unpack[AddressType]], Address] +from kwai.modules.club.domain.contact import ContactEntity +from kwai.modules.club.domain.country import CountryEntity +from kwai.modules.club.domain.value_objects import Address +from kwai.modules.club.repositories.contact_db_repository import ContactDbRepository @pytest.fixture -def make_address(country_japan) -> AddressFixtureFactory: +def make_address(country_japan): """A factory fixture for an address.""" def _make_address( @@ -56,18 +34,8 @@ def _make_address( return _make_address -class ContactType(TypedDict): - """Keyword arguments for the Contact fixture factory method.""" - - emails: NotRequired[list[EmailAddress]] - address: NotRequired[Address] - - -ContactFixtureFactory: TypeAlias = Callable[[Unpack[ContactType]], ContactEntity] - - @pytest.fixture -def make_emails() -> Callable[[str | None], list[EmailAddress]]: +def make_emails(): """A factory fixture for a contact email.""" def _make_emails(email: str | None = None) -> list[EmailAddress]: @@ -79,7 +47,7 @@ def _make_emails(email: str | None = None) -> list[EmailAddress]: @pytest.fixture -def make_contact(make_emails, make_address) -> ContactFixtureFactory: +def make_contact(make_emails, make_address): """A factory fixture for a contact.""" def _make_contact( @@ -93,11 +61,6 @@ def _make_contact( return _make_contact -ContactDbFixtureFactory: TypeAlias = Callable[ - [ContactEntity | None], Awaitable[ContactEntity] -] - - @pytest.fixture def make_contact_in_db( request, @@ -106,7 +69,7 @@ def make_contact_in_db( make_contact, make_address, make_country_in_db, -) -> ContactDbFixtureFactory: +): """A fixture for a contact in the database.""" async def _make_contact_in_db( diff --git a/backend/src/tests/fixtures/club/countries.py b/backend/src/tests/fixtures/club/countries.py index 549d14a72..f23d155c1 100644 --- a/backend/src/tests/fixtures/club/countries.py +++ b/backend/src/tests/fixtures/club/countries.py @@ -1,35 +1,16 @@ """Module for fixtures related to countries.""" -from typing import ( - AsyncGenerator, - Callable, - NotRequired, - TypedDict, - Unpack, -) - import pytest from kwai.core.db.database import Database from kwai.core.db.uow import UnitOfWork -from kwai.modules.club.members.country import CountryEntity -from kwai.modules.club.members.country_db_repository import CountryDbRepository -from kwai.modules.club.members.country_repository import CountryNotFoundException - - -class CountryType(TypedDict): - """Keyword arguments for the Country fixture factory method.""" - - iso_2: NotRequired[str] - iso_3: NotRequired[str] - name: NotRequired[str] - - -type CountryFixtureFactory = Callable[[Unpack[CountryType]], CountryEntity] +from kwai.modules.club.domain.country import CountryEntity +from kwai.modules.club.repositories.country_db_repository import CountryDbRepository +from kwai.modules.club.repositories.country_repository import CountryNotFoundException @pytest.fixture -def make_country() -> CountryFixtureFactory: +def make_country(): """A factory fixture for a country.""" def _make_country(iso_2="XX", iso_3="XXX", name="Test Country"): @@ -39,18 +20,13 @@ def _make_country(iso_2="XX", iso_3="XXX", name="Test Country"): @pytest.fixture -def country_japan() -> CountryEntity: +def country_japan(): """A factory fixture for the country Japan.""" return CountryEntity(iso_2="JP", iso_3="JPN", name="Japan") -type CountryDbFixtureFactory = Callable[[], AsyncGenerator[CountryEntity, None]] - - @pytest.fixture -async def make_country_in_db( - request, event_loop, database: Database, make_country: CountryFixtureFactory -) -> CountryDbFixtureFactory: +async def make_country_in_db(request, event_loop, database: Database, make_country): """A fixture for a country in the database. When the country is already in the database, it will be returned. diff --git a/backend/src/tests/fixtures/club/members.py b/backend/src/tests/fixtures/club/members.py index 049782754..8dfbcfbc7 100644 --- a/backend/src/tests/fixtures/club/members.py +++ b/backend/src/tests/fixtures/club/members.py @@ -1,22 +1,18 @@ """Module for defining fixtures of members.""" -from typing import Callable, TypeAlias - import pytest from kwai.core.db.database import Database from kwai.core.db.uow import UnitOfWork from kwai.core.domain.value_objects.date import Date -from kwai.modules.club.members.member import MemberEntity -from kwai.modules.club.members.member_db_repository import MemberDbRepository -from kwai.modules.club.members.person import PersonEntity -from kwai.modules.club.members.value_objects import License - -MemberFixtureFactory: TypeAlias = Callable[[License | None], MemberEntity] +from kwai.modules.club.domain.member import MemberEntity +from kwai.modules.club.domain.person import PersonEntity +from kwai.modules.club.domain.value_objects import License +from kwai.modules.club.repositories.member_db_repository import MemberDbRepository @pytest.fixture -def make_member(make_person) -> MemberFixtureFactory: +def make_member(make_person): """A factory fixture for a member.""" def _make_member_entity( @@ -41,11 +37,22 @@ def make_member_in_db( database: Database, make_member, make_person_in_db, + make_person, + make_contact_in_db, + make_country_in_db, + country_japan, ): """A fixture for a member in the database.""" async def _make_member_in_db(member: MemberEntity | None = None) -> MemberEntity: - member = member or make_member(person=await make_person_in_db()) + member = member or make_member( + person=await make_person_in_db( + make_person( + contact=await make_contact_in_db(), + nationality=await make_country_in_db(country_japan), + ), + ) + ) repo = MemberDbRepository(database) async with UnitOfWork(database): member = await repo.create(member) diff --git a/backend/src/tests/fixtures/club/persons.py b/backend/src/tests/fixtures/club/persons.py index 2244cc2e2..be24fe180 100644 --- a/backend/src/tests/fixtures/club/persons.py +++ b/backend/src/tests/fixtures/club/persons.py @@ -6,11 +6,11 @@ from kwai.core.db.uow import UnitOfWork from kwai.core.domain.value_objects.date import Date from kwai.core.domain.value_objects.name import Name -from kwai.modules.club.members.contact import ContactEntity -from kwai.modules.club.members.country import CountryEntity -from kwai.modules.club.members.person import PersonEntity -from kwai.modules.club.members.person_db_repository import PersonDbRepository -from kwai.modules.club.members.value_objects import Birthdate, Gender +from kwai.modules.club.domain.contact import ContactEntity +from kwai.modules.club.domain.country import CountryEntity +from kwai.modules.club.domain.person import PersonEntity +from kwai.modules.club.domain.value_objects import Birthdate, Gender +from kwai.modules.club.repositories.person_db_repository import PersonDbRepository @pytest.fixture diff --git a/backend/src/tests/fixtures/teams/__init__.py b/backend/src/tests/fixtures/teams/__init__.py new file mode 100644 index 000000000..533b46b01 --- /dev/null +++ b/backend/src/tests/fixtures/teams/__init__.py @@ -0,0 +1 @@ +"""Package for defining recurring fixtures for the teams bounded context.""" diff --git a/backend/src/tests/fixtures/teams/team_members.py b/backend/src/tests/fixtures/teams/team_members.py new file mode 100644 index 000000000..1ba087c82 --- /dev/null +++ b/backend/src/tests/fixtures/teams/team_members.py @@ -0,0 +1,50 @@ +"""Module for defining factory fixtures for team members.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.core.domain.value_objects.traceable_time import TraceableTime +from kwai.modules.teams.domain.team import TeamEntity +from kwai.modules.teams.domain.team_member import MemberEntity, TeamMember +from kwai.modules.teams.repositories.team_db_repository import TeamDbRepository + + +@pytest.fixture +def make_team_member(make_member): + """A factory fixture for a team member.""" + + def _make_team_member(member: MemberEntity | None = None) -> TeamMember: + member = member or make_member() + return TeamMember( + active=True, + member=MemberEntity( + id_=member.id, + uuid=member.uuid, + name=member.name, + license=member.license, + birthdate=member.person.birthdate, + nationality=member.person.nationality, + gender=member.person.gender, + ), + traceable_time=TraceableTime(), + ) + + return _make_team_member + + +@pytest.fixture +def make_team_member_in_db( + database: Database, make_team_member, make_member_in_db, make_team_in_db +): + """A factory fixture for a team member in a database.""" + + async def _make_team_member_in_db( + member: MemberEntity | None = None, team: TeamEntity | None = None + ) -> TeamMember: + member = member or make_team_member(await make_member_in_db()) + team = team or await make_team_in_db() + if team is not None: + await TeamDbRepository(database).add_team_member(team, member) + return member + + return _make_team_member_in_db diff --git a/backend/src/tests/fixtures/teams/teams.py b/backend/src/tests/fixtures/teams/teams.py new file mode 100644 index 000000000..599ef9db7 --- /dev/null +++ b/backend/src/tests/fixtures/teams/teams.py @@ -0,0 +1,42 @@ +"""Module for defining factory fixtures for teams.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.core.db.uow import UnitOfWork +from kwai.modules.teams.domain.team import TeamEntity +from kwai.modules.teams.repositories.team_db_repository import TeamDbRepository + + +@pytest.fixture +def make_team(): + """A factory fixture for creating a team.""" + + def _make_team(name: str | None = None) -> TeamEntity: + return TeamEntity(name=name or "U11") + + return _make_team + + +@pytest.fixture +def make_team_in_db(request, event_loop, database: Database, make_team): + """A factory fixture for creating a team in database.""" + + async def _make_team_in_db(team: TeamEntity | None = None) -> TeamEntity: + team = team or make_team() + repo = TeamDbRepository(database) + async with UnitOfWork(database): + team = await repo.create(team) + + def cleanup(): + async def acleanup(): + async with UnitOfWork(database): + await repo.delete(team) + + event_loop.run_until_complete(acleanup()) + + request.addfinalizer(cleanup) + + return team + + return _make_team_in_db diff --git a/backend/src/tests/fixtures/training/__init__.py b/backend/src/tests/fixtures/training/__init__.py new file mode 100644 index 000000000..f79555c49 --- /dev/null +++ b/backend/src/tests/fixtures/training/__init__.py @@ -0,0 +1 @@ +"""Package for defining recurring fixtures for the training bounded context.""" diff --git a/backend/src/tests/fixtures/training/training_definitions.py b/backend/src/tests/fixtures/training/training_definitions.py new file mode 100644 index 000000000..0d00cc1fa --- /dev/null +++ b/backend/src/tests/fixtures/training/training_definitions.py @@ -0,0 +1,63 @@ +"""Module for defining fixture factories for training definitions.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.core.db.uow import UnitOfWork +from kwai.core.domain.value_objects.owner import Owner +from kwai.core.domain.value_objects.time_period import TimePeriod +from kwai.core.domain.value_objects.weekday import Weekday +from kwai.modules.training.trainings.training_definition import TrainingDefinitionEntity +from kwai.modules.training.trainings.training_definition_db_repository import ( + TrainingDefinitionDbRepository, +) + + +@pytest.fixture +def make_training_definition(owner: Owner): + """A factory fixture for creating a training definition.""" + + def _make_training_definition( + name: str | None = None, + description: str | None = None, + weekday: Weekday | None = None, + period: TimePeriod | None = None, + ) -> TrainingDefinitionEntity: + return TrainingDefinitionEntity( + name=name or "A training", + description=description or "A training definition", + weekday=weekday or Weekday.MONDAY, + period=period + or TimePeriod.create_from_string("18:00", "19:00", "Europe/Brussels"), + owner=owner, + ) + + return _make_training_definition + + +@pytest.fixture +def make_training_definition_in_db( + request, event_loop, database: Database, make_training_definition +): + """A fixture factory for a training definition in the database.""" + + async def _make_training_definition_in_db( + training_definition: TrainingDefinitionEntity | None = None, + ) -> TrainingDefinitionEntity: + training_definition = training_definition or make_training_definition() + repo = TrainingDefinitionDbRepository(database) + async with UnitOfWork(database): + training_definition = await repo.create(training_definition) + + def cleanup(): + async def acleanup(): + async with UnitOfWork(database): + await repo.delete(training_definition) + + event_loop.run_until_complete(acleanup()) + + request.addfinalizer(cleanup) + + return training_definition + + return _make_training_definition_in_db diff --git a/backend/src/tests/fixtures/training/trainings.py b/backend/src/tests/fixtures/training/trainings.py new file mode 100644 index 000000000..fcb9990ae --- /dev/null +++ b/backend/src/tests/fixtures/training/trainings.py @@ -0,0 +1,98 @@ +"""Module for defining factory fixtures for trainings.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.core.db.uow import UnitOfWork +from kwai.core.domain.value_objects.owner import Owner +from kwai.core.domain.value_objects.period import Period +from kwai.core.domain.value_objects.text import DocumentFormat, Locale, LocaleText +from kwai.modules.training.coaches.coach import CoachEntity +from kwai.modules.training.trainings.training import TrainingEntity +from kwai.modules.training.trainings.training_db_repository import TrainingDbRepository +from kwai.modules.training.trainings.value_objects import TrainingCoach + + +@pytest.fixture +def make_text( + *, + locale: Locale | None = None, + format_: DocumentFormat | None = None, + title: str = "Training Test", + content: str = "This is a test training", + summary: str = "Test", + owner: Owner, +): + """A factory fixture for a text.""" + + def _make_text() -> LocaleText: + return LocaleText( + title=title, + content=content, + summary=summary, + locale=locale or Locale.NL, + format=format_ or DocumentFormat.MARKDOWN, + author=owner, + ) + + return _make_text + + +@pytest.fixture +def make_training_coach(make_coach, owner: Owner): + """A factory fixture for a training coach.""" + + def _make_training_coach(coach: CoachEntity | None = None) -> TrainingCoach: + if coach is None: + # make_coach returns a coach entity from the club module, so we need + # to convert it to one for the training module. + club_coach = make_coach() + coach = CoachEntity( + id_=club_coach.id, name=club_coach.name, active=club_coach.is_active + ) + return TrainingCoach(coach=coach, owner=owner) + + return _make_training_coach + + +@pytest.fixture +def make_training(make_text, make_training_coach): + """A factory fixture for a training.""" + + def _make_training( + text: LocaleText | None = None, + coach: TrainingCoach | None = None, + period: Period | None = None, + ) -> TrainingEntity: + coach = coach or make_training_coach() + text = text or make_text() + period = period or Period.create_from_delta(hours=2) + return TrainingEntity(texts=[text], coaches=[coach], season=None, period=period) + + return _make_training + + +@pytest.fixture +def make_training_in_db(request, event_loop, database: Database, make_training): + """A factory fixture for a training in the database.""" + + async def _make_training_in_db( + training: TrainingEntity | None = None, + ) -> TrainingEntity: + training = training or make_training() + repo = TrainingDbRepository(database) + async with UnitOfWork(database): + training = await repo.create(training) + + def cleanup(): + async def acleanup(): + async with UnitOfWork(database): + await repo.delete(training) + + event_loop.run_until_complete(acleanup()) + + request.addfinalizer(cleanup) + + return training + + return _make_training_in_db diff --git a/backend/src/tests/frontend/__init__.py b/backend/src/tests/frontend/__init__.py new file mode 100644 index 000000000..cfbb3982c --- /dev/null +++ b/backend/src/tests/frontend/__init__.py @@ -0,0 +1 @@ +"""Package containing frontend tests.""" diff --git a/backend/src/tests/frontend/conftest.py b/backend/src/tests/frontend/conftest.py new file mode 100644 index 000000000..b0d6d6123 --- /dev/null +++ b/backend/src/tests/frontend/conftest.py @@ -0,0 +1,19 @@ +"""Module for pytest fixtures for testing the frontend module..""" + +from pathlib import Path + +import pytest + +from kwai.frontend.manifest import Manifest + + +@pytest.fixture +def manifest_path() -> Path: + """Load a manifest file from the data folder.""" + return Path(__file__).parent / "data" / "manifest.json" + + +@pytest.fixture +def manifest(manifest_path) -> Manifest: + """Load a manifest file from the data folder.""" + return Manifest.load_from_file(manifest_path) diff --git a/backend/src/tests/frontend/data/manifest.json b/backend/src/tests/frontend/data/manifest.json new file mode 100644 index 000000000..2d070f0a0 --- /dev/null +++ b/backend/src/tests/frontend/data/manifest.json @@ -0,0 +1,114 @@ +{ + "_vendor-97e41b2b.js": { + "file": "assets/vendor-97e41b2b.js" + }, + "images/hero.jpg": { + "file": "assets/hero-7d6583ab.jpg", + "src": "images/hero.jpg" + }, + "images/hero_club.jpg": { + "file": "assets/hero_club-163a0a1d.jpg", + "src": "images/hero_club.jpg" + }, + "images/hero_judo.jpg": { + "file": "assets/hero_judo-98309ea4.jpg", + "src": "images/hero_judo.jpg" + }, + "images/hero_news.jpg": { + "file": "assets/hero_news-7e409a2c.jpg", + "src": "images/hero_news.jpg" + }, + "images/hero_shop.jpg": { + "file": "assets/hero_shop-b55abed0.jpg", + "src": "images/hero_shop.jpg" + }, + "images/hero_tournaments.jpg": { + "file": "assets/hero_tournaments-59e5271e.jpg", + "src": "images/hero_tournaments.jpg" + }, + "images/hero_trainings.jpg": { + "file": "assets/hero_trainings-47dcea06.jpg", + "src": "images/hero_trainings.jpg" + }, + "src/components/icons/FacebookIcon.vue": { + "file": "assets/FacebookIcon-44b697a2.js", + "imports": [ + "src/index.ts", + "_vendor-97e41b2b.js" + ], + "isDynamicEntry": true, + "src": "src/components/icons/FacebookIcon.vue" + }, + "src/components/icons/InstagramIcon.vue": { + "file": "assets/InstagramIcon-ce6d9dfa.js", + "imports": [ + "src/index.ts", + "_vendor-97e41b2b.js" + ], + "isDynamicEntry": true, + "src": "src/components/icons/InstagramIcon.vue" + }, + "src/components/icons/LoadingIcon.vue": { + "file": "assets/LoadingIcon-3b690cc8.js", + "imports": [ + "src/index.ts", + "_vendor-97e41b2b.js" + ], + "isDynamicEntry": true, + "src": "src/components/icons/LoadingIcon.vue" + }, + "src/components/icons/NextIcon.vue": { + "file": "assets/NextIcon-771d3f7f.js", + "imports": [ + "src/index.ts", + "_vendor-97e41b2b.js" + ], + "isDynamicEntry": true, + "src": "src/components/icons/NextIcon.vue" + }, + "src/components/icons/PrevIcon.vue": { + "file": "assets/PrevIcon-41277b2b.js", + "imports": [ + "src/index.ts", + "_vendor-97e41b2b.js" + ], + "isDynamicEntry": true, + "src": "src/components/icons/PrevIcon.vue" + }, + "src/index.css": { + "file": "assets/index-ace45c09.css", + "src": "src/index.css" + }, + "src/index.ts": { + "assets": [ + "assets/hero-7d6583ab.jpg", + "assets/hero_club-163a0a1d.jpg", + "assets/hero_judo-98309ea4.jpg", + "assets/hero_news-7e409a2c.jpg", + "assets/hero_shop-b55abed0.jpg", + "assets/hero_tournaments-59e5271e.jpg", + "assets/hero_trainings-47dcea06.jpg" + ], + "css": [ + "assets/index-ace45c09.css" + ], + "dynamicImports": [ + "src/components/icons/FacebookIcon.vue", + "src/components/icons/InstagramIcon.vue", + "src/components/icons/LoadingIcon.vue", + "src/components/icons/NextIcon.vue", + "src/components/icons/PrevIcon.vue", + "src/components/icons/FacebookIcon.vue", + "src/components/icons/InstagramIcon.vue", + "src/components/icons/LoadingIcon.vue", + "src/components/icons/NextIcon.vue", + "src/components/icons/PrevIcon.vue" + ], + "file": "assets/index-533fa9ea.js", + "imports": [ + "_vendor-97e41b2b.js" + ], + "isEntry": true, + "src": "src/index.ts" + } +} diff --git a/backend/src/tests/frontend/test_development_vite.py b/backend/src/tests/frontend/test_development_vite.py new file mode 100644 index 000000000..57301d246 --- /dev/null +++ b/backend/src/tests/frontend/test_development_vite.py @@ -0,0 +1,31 @@ +"""Module for testing the development vite class.""" + +import pytest + +from kwai.frontend.vite import DevelopmentVite, Vite + + +@pytest.fixture +def vite() -> Vite: + """A fixture for vite development.""" + vite = DevelopmentVite("http://localhost:5173", "") + vite.init("src/index.ts") + return vite + + +def test_development_vite_scripts(vite: Vite): + """Test the development version of the Vite class for script tags.""" + scripts = vite.get_scripts("") + assert len(scripts) == 2, "There should be 2 script tags" + assert scripts[0] == "http://localhost:5173/@vite/client" + assert scripts[1] == "http://localhost:5173/src/index.ts" + + +def test_development_vite_css(vite: Vite): + """Test the development version of the Vite class for css tags.""" + assert len(vite.get_css("")) == 0, "There should be no css in development" + + +def test_development_vite_preload(vite: Vite): + """Test the development version of the Vite class for preload tags.""" + assert len(vite.get_preloads("")) == 0, "There should be no preload in development" diff --git a/backend/src/tests/frontend/test_etag_file_response.py b/backend/src/tests/frontend/test_etag_file_response.py new file mode 100644 index 000000000..f66470909 --- /dev/null +++ b/backend/src/tests/frontend/test_etag_file_response.py @@ -0,0 +1,31 @@ +"""Test the EtagFileResponse.""" + +from pathlib import Path + +from fastapi import FastAPI +from fastapi.testclient import TestClient + +from kwai.frontend.etag_file_response import EtagFileResponse + + +def test_etag_file_response(tmp_path: Path) -> None: + """Test the ETag file response.""" + app = FastAPI(title="kwai API -- TEST") + + @app.get("/") + def get_file(): + return EtagFileResponse(tmp_path / "test_file.txt") + + client = TestClient(app) + + test_file_path = Path(tmp_path / "test_file.txt") + with open(test_file_path, "w") as f: + f.write("This is a test file.") + + response = client.get("/") + assert response.status_code == 200 + assert response.headers["Etag"] is not None + + etag = response.headers["Etag"] + response = client.get("/", headers={"if-none-match": etag}) + assert response.status_code == 304 diff --git a/backend/src/tests/frontend/test_manifest.py b/backend/src/tests/frontend/test_manifest.py new file mode 100644 index 000000000..9bd0e96d8 --- /dev/null +++ b/backend/src/tests/frontend/test_manifest.py @@ -0,0 +1,47 @@ +"""Module for testing the Manifest class.""" + +from kwai.frontend.manifest import Manifest + + +def test_load_manifest_from_string(): + """Test loading the manifest from a string.""" + manifest = Manifest.load_from_string( + """ + { + "src/index.ts": { + "isEntry": true, + "file": "assets/index-8a61960c.js", + "src": "src/index.ts" + } + } + """ + ) + assert len(manifest.chunks) > 0, "There should be a chunk in the manifest." + assert manifest.has_chunk("src/index.ts") is not None, "The chunk should exist." + assert manifest.get_chunk("src/index.ts") is not None, "The chunk should exist." + + +def test_chunks(manifest: Manifest): + """Test the chunks property.""" + chunks = manifest.chunks + assert len(chunks) > 0, "There should be chunks in the manifest." + + +def test_has_chunk(manifest: Manifest): + """Test the has_chunk method.""" + assert manifest.has_chunk("src/index.ts") is True, "The chunk should exist." + assert manifest.has_chunk("images/hero.jpg") is True, "The chunk should exist." + + +def test_chunk(manifest: Manifest): + """Test the get_chunk method.""" + chunk = manifest.get_chunk("src/index.ts") + assert chunk is not None, "The chunk should exist." + assert chunk.src == "src/index.ts", "The src should be 'src/index.ts'" + assert chunk.file == "assets/index-533fa9ea.js" + assert len(chunk.imports) > 0 + assert chunk.entry is True + assert len(chunk.assets) > 0 + assert len(chunk.css) > 0 + assert len(chunk.dynamic_imports) > 0 + assert chunk.dynamic_entry is False diff --git a/backend/src/tests/frontend/test_production_vite.py b/backend/src/tests/frontend/test_production_vite.py new file mode 100644 index 000000000..027e8a85d --- /dev/null +++ b/backend/src/tests/frontend/test_production_vite.py @@ -0,0 +1,69 @@ +"""Module for testing the production vite class.""" + +from pathlib import Path + +import pytest + +from kwai.frontend.vite import ProductionVite, Vite + + +@pytest.fixture +def vite(manifest_path: Path, tmp_path: Path) -> Vite: + """A fixture for vite production.""" + vite = ProductionVite(manifest_path, tmp_path) + vite.init("src/index.ts") + return vite + + +def test_production_vite_scripts(vite: Vite): + """Test the production version of the Vite class for script tags.""" + scripts = vite.get_scripts("http://localhost:8000/apps/portal/") + assert len(scripts) == 1, "There should be one script tag" + assert scripts[0] == "http://localhost:8000/apps/portal/assets/index-533fa9ea.js" + + +def test_production_vite_css(vite: Vite): + """Test the production of the Vite class for css tags.""" + css = vite.get_css("") + assert len(css) == 1, "There should be a css link" + assert css[0] == "assets/index-ace45c09.css" + + +def test_production_vite_preload(vite: Vite): + """Test the production version of the Vite class for preload tags.""" + preload = vite.get_preloads("") + assert len(preload) == 1, "There should be a preload" + assert preload[0] == "assets/vendor-97e41b2b.js" + + +def test_production_vite_get_asset_path(vite: Vite, tmp_path: Path): + """Test getting the path of an asset.""" + dist_path = tmp_path / "dist" + dist_path.mkdir(exist_ok=True) + with open(dist_path / "test_file.txt", "w") as f: + f.write("This is a test file.") + + asset_file = vite.get_asset_path(Path("test_file.txt")) + assert asset_file is not None + + +def test_production_vite_get_public_path(vite: Vite, tmp_path: Path): + """Test getting the path of a public file.""" + dist_path = tmp_path / "dist" + dist_path.mkdir(exist_ok=True) + with open(dist_path / "test_file.txt", "w") as f: + f.write("This is a test file.") + + asset_file = vite.get_asset_path(Path("test_file.txt")) + assert asset_file is not None + + +def test_production_vite_get_asset_path_with_relative(vite: Vite, tmp_path: Path): + """Test if a relative path fails.""" + dist_path = tmp_path / "dist" + dist_path.mkdir(exist_ok=True) + with open(dist_path / "test_file.txt", "w") as f: + f.write("This is a test file.") + + asset_file = vite.get_asset_path(Path("../../test_file.txt")) + assert asset_file is None diff --git a/backend/src/tests/modules/club/conftest.py b/backend/src/tests/modules/club/conftest.py index 4824b39d3..f79f4fa28 100644 --- a/backend/src/tests/modules/club/conftest.py +++ b/backend/src/tests/modules/club/conftest.py @@ -1,6 +1,7 @@ -"""Module for defining common fixtures for testing code related to members.""" +"""Module for common fixtures used for testing code of the club module.""" from tests.fixtures.club.countries import * # noqa from tests.fixtures.club.contacts import * # noqa from tests.fixtures.club.persons import * # noqa from tests.fixtures.club.members import * # noqa +from tests.fixtures.club.coaches import * # noqa diff --git a/backend/src/tests/modules/club/domain/__init__.py b/backend/src/tests/modules/club/domain/__init__.py new file mode 100644 index 000000000..b862f7c7d --- /dev/null +++ b/backend/src/tests/modules/club/domain/__init__.py @@ -0,0 +1 @@ +"""Package for testing the club domain package.""" diff --git a/backend/src/tests/modules/club/members/test_birthdate.py b/backend/src/tests/modules/club/domain/test_birthdate.py similarity index 92% rename from backend/src/tests/modules/club/members/test_birthdate.py rename to backend/src/tests/modules/club/domain/test_birthdate.py index d22d22af6..272cd2e99 100644 --- a/backend/src/tests/modules/club/members/test_birthdate.py +++ b/backend/src/tests/modules/club/domain/test_birthdate.py @@ -3,7 +3,7 @@ import pendulum from kwai.core.domain.value_objects.date import Date -from kwai.modules.club.members.value_objects import Birthdate +from kwai.modules.club.domain.value_objects import Birthdate def test_age(): diff --git a/backend/src/tests/modules/club/members/test_contact.py b/backend/src/tests/modules/club/domain/test_contact.py similarity index 87% rename from backend/src/tests/modules/club/members/test_contact.py rename to backend/src/tests/modules/club/domain/test_contact.py index 2d0735faa..80ebcf4fe 100644 --- a/backend/src/tests/modules/club/members/test_contact.py +++ b/backend/src/tests/modules/club/domain/test_contact.py @@ -3,9 +3,9 @@ import pytest from kwai.core.domain.value_objects.email_address import EmailAddress -from kwai.modules.club.members.contact import ContactEntity -from kwai.modules.club.members.country import CountryEntity, CountryIdentifier -from kwai.modules.club.members.value_objects import Address +from kwai.modules.club.domain.contact import ContactEntity +from kwai.modules.club.domain.country import CountryEntity, CountryIdentifier +from kwai.modules.club.domain.value_objects import Address @pytest.fixture diff --git a/backend/src/tests/modules/club/repositories/__init__.py b/backend/src/tests/modules/club/repositories/__init__.py new file mode 100644 index 000000000..b36b28844 --- /dev/null +++ b/backend/src/tests/modules/club/repositories/__init__.py @@ -0,0 +1 @@ +"""Package for testing the club repositories.""" diff --git a/backend/src/tests/modules/club/members/data/flemish_members_test.csv b/backend/src/tests/modules/club/repositories/data/flemish_members_test.csv similarity index 100% rename from backend/src/tests/modules/club/members/data/flemish_members_test.csv rename to backend/src/tests/modules/club/repositories/data/flemish_members_test.csv diff --git a/backend/src/tests/modules/club/repositories/test_coach_db_repository.py b/backend/src/tests/modules/club/repositories/test_coach_db_repository.py new file mode 100644 index 000000000..b3ab0c46c --- /dev/null +++ b/backend/src/tests/modules/club/repositories/test_coach_db_repository.py @@ -0,0 +1,12 @@ +"""Module for testing the coach database repository.""" + +import pytest + +pytestmark = pytest.mark.db + + +async def test_create_coach(make_coach_in_db, make_member_in_db): + """Test creating a coach.""" + coach = await make_coach_in_db() + assert coach is not None, "There should be a coach." + assert coach.id is not None, "Coach id should be provided." diff --git a/backend/src/tests/modules/club/members/test_contact_db_repository.py b/backend/src/tests/modules/club/repositories/test_contact_db_repository.py similarity index 92% rename from backend/src/tests/modules/club/members/test_contact_db_repository.py rename to backend/src/tests/modules/club/repositories/test_contact_db_repository.py index 39f7b2d08..b42c360dc 100644 --- a/backend/src/tests/modules/club/members/test_contact_db_repository.py +++ b/backend/src/tests/modules/club/repositories/test_contact_db_repository.py @@ -5,8 +5,8 @@ from kwai.core.db.database import Database from kwai.core.db.uow import UnitOfWork from kwai.core.domain.entity import Entity -from kwai.modules.club.members.contact_db_repository import ContactDbRepository -from kwai.modules.club.members.contact_repository import ( +from kwai.modules.club.repositories.contact_db_repository import ContactDbRepository +from kwai.modules.club.repositories.contact_repository import ( ContactNotFoundException, ContactRepository, ) diff --git a/backend/src/tests/modules/club/members/test_country_db_repository.py b/backend/src/tests/modules/club/repositories/test_country_db_repository.py similarity index 86% rename from backend/src/tests/modules/club/members/test_country_db_repository.py rename to backend/src/tests/modules/club/repositories/test_country_db_repository.py index ae594a096..e101e7519 100644 --- a/backend/src/tests/modules/club/members/test_country_db_repository.py +++ b/backend/src/tests/modules/club/repositories/test_country_db_repository.py @@ -3,9 +3,9 @@ import pytest from kwai.core.db.database import Database -from kwai.modules.club.members.country import CountryEntity -from kwai.modules.club.members.country_db_repository import CountryDbRepository -from kwai.modules.club.members.country_repository import ( +from kwai.modules.club.domain.country import CountryEntity +from kwai.modules.club.repositories.country_db_repository import CountryDbRepository +from kwai.modules.club.repositories.country_repository import ( CountryNotFoundException, CountryRepository, ) diff --git a/backend/src/tests/modules/club/members/test_file_upload_db_repository.py b/backend/src/tests/modules/club/repositories/test_file_upload_db_repository.py similarity index 75% rename from backend/src/tests/modules/club/members/test_file_upload_db_repository.py rename to backend/src/tests/modules/club/repositories/test_file_upload_db_repository.py index 797285b59..376f84813 100644 --- a/backend/src/tests/modules/club/members/test_file_upload_db_repository.py +++ b/backend/src/tests/modules/club/repositories/test_file_upload_db_repository.py @@ -4,8 +4,10 @@ from kwai.core.db.database import Database from kwai.core.domain.value_objects.owner import Owner -from kwai.modules.club.members.file_upload import FileUploadEntity -from kwai.modules.club.members.file_upload_db_repository import FileUploadDbRepository +from kwai.modules.club.domain.file_upload import FileUploadEntity +from kwai.modules.club.repositories.file_upload_db_repository import ( + FileUploadDbRepository, +) pytestmark = pytest.mark.db diff --git a/backend/src/tests/modules/club/members/test_flemish_member_importer.py b/backend/src/tests/modules/club/repositories/test_flemish_member_importer.py similarity index 79% rename from backend/src/tests/modules/club/members/test_flemish_member_importer.py rename to backend/src/tests/modules/club/repositories/test_flemish_member_importer.py index 6eb572298..d80b78ecc 100644 --- a/backend/src/tests/modules/club/members/test_flemish_member_importer.py +++ b/backend/src/tests/modules/club/repositories/test_flemish_member_importer.py @@ -6,10 +6,10 @@ from kwai.core.db.database import Database from kwai.core.domain.value_objects.owner import Owner -from kwai.modules.club.members.country_db_repository import CountryDbRepository -from kwai.modules.club.members.flemish_member_importer import FlemishMemberImporter -from kwai.modules.club.members.member_importer import Result -from kwai.modules.club.members.value_objects import Gender +from kwai.modules.club.domain.value_objects import Gender +from kwai.modules.club.repositories.country_db_repository import CountryDbRepository +from kwai.modules.club.repositories.flemish_member_importer import FlemishMemberImporter +from kwai.modules.club.repositories.member_importer import Result pytestmark = pytest.mark.db diff --git a/backend/src/tests/modules/club/members/test_member_db_query.py b/backend/src/tests/modules/club/repositories/test_member_db_query.py similarity index 89% rename from backend/src/tests/modules/club/members/test_member_db_query.py rename to backend/src/tests/modules/club/repositories/test_member_db_query.py index 37db0a439..cc02cb6ea 100644 --- a/backend/src/tests/modules/club/members/test_member_db_query.py +++ b/backend/src/tests/modules/club/repositories/test_member_db_query.py @@ -4,9 +4,9 @@ from kwai.core.db.database import Database from kwai.core.domain.value_objects.unique_id import UniqueId -from kwai.modules.club.members.member import MemberIdentifier -from kwai.modules.club.members.member_db_query import MemberDbQuery -from kwai.modules.club.members.member_query import MemberQuery +from kwai.modules.club.domain.member import MemberIdentifier +from kwai.modules.club.repositories.member_db_query import MemberDbQuery +from kwai.modules.club.repositories.member_query import MemberQuery pytestmark = pytest.mark.db diff --git a/backend/src/tests/modules/club/members/test_member_db_repository.py b/backend/src/tests/modules/club/repositories/test_member_db_repository.py similarity index 62% rename from backend/src/tests/modules/club/members/test_member_db_repository.py rename to backend/src/tests/modules/club/repositories/test_member_db_repository.py index a1c461224..6405571ba 100644 --- a/backend/src/tests/modules/club/members/test_member_db_repository.py +++ b/backend/src/tests/modules/club/repositories/test_member_db_repository.py @@ -5,8 +5,10 @@ from kwai.core.db.database import Database from kwai.core.db.uow import UnitOfWork from kwai.core.domain.entity import Entity -from kwai.modules.club.members.member_db_repository import MemberDbRepository -from kwai.modules.club.members.member_repository import ( +from kwai.core.domain.value_objects.owner import Owner +from kwai.modules.club.domain.file_upload import FileUploadEntity, FileUploadIdentifier +from kwai.modules.club.repositories.member_db_repository import MemberDbRepository +from kwai.modules.club.repositories.member_repository import ( MemberNotFoundException, MemberRepository, ) @@ -57,3 +59,29 @@ async def test_delete( await member_repo.delete(member) with pytest.raises(MemberNotFoundException): await member_repo.get(member_repo.create_query().filter_by_id(member.id)) + + +async def test_activate_members( + member_repo: MemberRepository, database: Database, owner: Owner +): + """Test activate members.""" + async with UnitOfWork(database): + upload_entity = FileUploadEntity( + id_=FileUploadIdentifier(1), + filename="test.txt", + owner=owner, + ) + await member_repo.activate_members(upload_entity) + + +async def test_deactivate_members( + member_repo: MemberRepository, database: Database, owner: Owner +): + """Test activate members.""" + async with UnitOfWork(database): + upload_entity = FileUploadEntity( + id_=FileUploadIdentifier(1), + filename="test.txt", + owner=owner, + ) + await member_repo.deactivate_members(upload_entity) diff --git a/backend/src/tests/modules/club/members/test_person_db_repository.py b/backend/src/tests/modules/club/repositories/test_person_db_repository.py similarity index 92% rename from backend/src/tests/modules/club/members/test_person_db_repository.py rename to backend/src/tests/modules/club/repositories/test_person_db_repository.py index 40885d214..77a29a884 100644 --- a/backend/src/tests/modules/club/members/test_person_db_repository.py +++ b/backend/src/tests/modules/club/repositories/test_person_db_repository.py @@ -5,8 +5,8 @@ from kwai.core.db.database import Database from kwai.core.db.uow import UnitOfWork from kwai.core.domain.entity import Entity -from kwai.modules.club.members.person_db_repository import PersonDbRepository -from kwai.modules.club.members.person_repository import ( +from kwai.modules.club.repositories.person_db_repository import PersonDbRepository +from kwai.modules.club.repositories.person_repository import ( PersonNotFoundException, PersonRepository, ) diff --git a/backend/src/tests/modules/club/test_get_member.py b/backend/src/tests/modules/club/test_get_member.py index 5ddf16454..7df4a25ba 100644 --- a/backend/src/tests/modules/club/test_get_member.py +++ b/backend/src/tests/modules/club/test_get_member.py @@ -3,9 +3,28 @@ import pytest from kwai.core.db.database import Database +from kwai.core.domain.presenter import Presenter +from kwai.modules.club.domain.member import MemberEntity from kwai.modules.club.get_member import GetMember, GetMemberCommand -from kwai.modules.club.members.member_db_repository import MemberDbRepository -from kwai.modules.club.members.member_repository import MemberRepository +from kwai.modules.club.repositories.member_db_repository import MemberDbRepository +from kwai.modules.club.repositories.member_repository import MemberRepository + + +class TestPresenter(Presenter[MemberEntity]): + """A dummy presenter for checking the use case result.""" + + def __init__(self): + super().__init__() + self._entity = None + + @property + def entity(self): + """Return the entity.""" + return self._entity + + def present(self, use_case_result: MemberEntity) -> None: + """Process the result of the use case.""" + self._entity = use_case_result @pytest.fixture @@ -17,6 +36,8 @@ def member_repo(database: Database) -> MemberRepository: async def test_get_member(member_repo: MemberRepository, make_member_in_db): """Test the get member use case.""" member = await make_member_in_db() + presenter = TestPresenter() command = GetMemberCommand(uuid=str(member.uuid)) - result = await GetMember(member_repo).execute(command) - assert result.uuid == member.uuid, "The member should be found" + await GetMember(member_repo, presenter).execute(command) + assert presenter.entity is not None, "The member should exist" + assert presenter.entity.uuid == member.uuid, "The member should be found" diff --git a/backend/src/tests/modules/club/test_get_members.py b/backend/src/tests/modules/club/test_get_members.py index 9d29f7210..8b7a00ad4 100644 --- a/backend/src/tests/modules/club/test_get_members.py +++ b/backend/src/tests/modules/club/test_get_members.py @@ -3,11 +3,30 @@ import pytest from kwai.core.db.database import Database +from kwai.core.domain.presenter import AsyncPresenter, IterableResult from kwai.core.domain.value_objects.date import Date +from kwai.modules.club.domain.member import MemberEntity +from kwai.modules.club.domain.value_objects import License from kwai.modules.club.get_members import GetMembers, GetMembersCommand -from kwai.modules.club.members.member_db_repository import MemberDbRepository -from kwai.modules.club.members.member_repository import MemberRepository -from kwai.modules.club.members.value_objects import License +from kwai.modules.club.repositories.member_db_repository import MemberDbRepository +from kwai.modules.club.repositories.member_repository import MemberRepository + + +class DummyPresenter(AsyncPresenter[IterableResult[MemberEntity]]): + """A dummy presenter for checking the use case result.""" + + def __init__(self): + super().__init__() + self._count = 0 + + @property + def count(self): + """Return count.""" + return self._count + + async def present(self, use_case_result: IterableResult[MemberEntity]) -> None: + """Process the result of the use case.""" + self._count += 1 @pytest.fixture @@ -20,8 +39,9 @@ async def test_get_members(member_repo: MemberRepository, make_member_in_db): """Test get members.""" await make_member_in_db() command = GetMembersCommand() - result = await GetMembers(member_repo).execute(command) - assert result.count > 0, "There should be at least one member" + presenter = DummyPresenter() + await GetMembers(member_repo, presenter).execute(command) + assert presenter.count > 0, "There should be at least one member" async def test_get_members_with_license_date( @@ -35,8 +55,9 @@ async def test_get_members_with_license_date( ) ) command = GetMembersCommand(license_end_year=2023, license_end_month=2) - result = await GetMembers(member_repo).execute(command) - assert result.count == 1, "There should only be one member" + presenter = DummyPresenter() + await GetMembers(member_repo, presenter).execute(command) + assert presenter.count == 1, "There should only be one member" async def test_get_all_members( @@ -50,5 +71,6 @@ async def test_get_all_members( ) ) command = GetMembersCommand(active=False) - result = await GetMembers(member_repo).execute(command) - assert result.count > 0, "There should be at least one inactive member" + presenter = DummyPresenter() + await GetMembers(member_repo, presenter).execute(command) + assert presenter.count > 0, "There should be at least one inactive member" diff --git a/backend/src/tests/modules/club/test_import_members.py b/backend/src/tests/modules/club/test_import_members.py index ceceaca0b..b9aa474bf 100644 --- a/backend/src/tests/modules/club/test_import_members.py +++ b/backend/src/tests/modules/club/test_import_members.py @@ -3,24 +3,51 @@ from pathlib import Path from kwai.core.db.database import Database +from kwai.core.domain.presenter import Presenter from kwai.core.domain.value_objects.owner import Owner from kwai.modules.club.import_members import ImportMembers, ImportMembersCommand -from kwai.modules.club.members.country_db_repository import CountryDbRepository -from kwai.modules.club.members.file_upload_db_repository import FileUploadDbRepository -from kwai.modules.club.members.flemish_member_importer import FlemishMemberImporter -from kwai.modules.club.members.member_db_repository import MemberDbRepository +from kwai.modules.club.repositories.country_db_repository import CountryDbRepository +from kwai.modules.club.repositories.file_upload_db_repository import ( + FileUploadDbRepository, +) +from kwai.modules.club.repositories.flemish_member_importer import FlemishMemberImporter +from kwai.modules.club.repositories.member_db_repository import MemberDbRepository + + +class DummyPresenter[MemberImportResult](Presenter): + """A dummy presenter.""" + + def __init__(self): + super().__init__() + self._count = 0 + + @property + def count(self): + """Return the count.""" + return self._count + + def present(self, use_case_result: MemberImportResult) -> None: + """Process the result of the use case.""" + self._count += 1 async def test_import_members(database: Database, owner: Owner): """Test the use case Import Members.""" - filename = Path(__file__).parent / "members" / "data" / "flemish_members_test.csv" + filename = ( + Path(__file__).parent / "repositories" / "data" / "flemish_members_test.csv" + ) importer = FlemishMemberImporter( str(filename), owner, CountryDbRepository(database) ) command = ImportMembersCommand() - async for result in ImportMembers( - importer, FileUploadDbRepository(database), MemberDbRepository(database) - ).execute(command): - assert result.file_upload is not None, "There should be a fileupload result" + presenter = DummyPresenter() + await ImportMembers( + importer, + FileUploadDbRepository(database), + MemberDbRepository(database), + presenter, + ).execute(command) + + assert presenter.count > 0, "There should be a member uploaded." diff --git a/backend/src/tests/modules/identity/tokens/conftest.py b/backend/src/tests/modules/identity/tokens/conftest.py index e59dfc783..06215103f 100644 --- a/backend/src/tests/modules/identity/tokens/conftest.py +++ b/backend/src/tests/modules/identity/tokens/conftest.py @@ -1,9 +1,9 @@ """Module that defines fixtures for testing identity tokens.""" -from datetime import datetime import pytest from kwai.core.db.database import Database +from kwai.core.domain.value_objects.timestamp import Timestamp from kwai.modules.identity.tokens.access_token import ( AccessTokenEntity, ) @@ -33,7 +33,7 @@ async def access_token( """Fixture for creating an access token.""" token = AccessTokenEntity( identifier=TokenIdentifier.generate(), - expiration=datetime.utcnow(), + expiration=Timestamp.create_now(), user_account=user_account, ) @@ -53,7 +53,7 @@ async def refresh_token( """Fixture for creating a refresh token.""" token = RefreshTokenEntity( identifier=TokenIdentifier.generate(), - expiration=datetime.utcnow(), + expiration=Timestamp.create_now(), access_token=access_token, ) return await refresh_token_repo.create(token) diff --git a/backend/src/tests/modules/identity/tokens/test_access_token.py b/backend/src/tests/modules/identity/tokens/test_access_token.py index 16b21da4b..d82507c42 100644 --- a/backend/src/tests/modules/identity/tokens/test_access_token.py +++ b/backend/src/tests/modules/identity/tokens/test_access_token.py @@ -1,9 +1,9 @@ """Module for testing the access token entity.""" -from datetime import datetime from kwai.core.domain.value_objects.email_address import EmailAddress from kwai.core.domain.value_objects.name import Name from kwai.core.domain.value_objects.password import Password +from kwai.core.domain.value_objects.timestamp import Timestamp from kwai.core.domain.value_objects.unique_id import UniqueId from kwai.modules.identity.tokens.access_token import AccessTokenEntity from kwai.modules.identity.tokens.token_identifier import TokenIdentifier @@ -23,7 +23,7 @@ def test_create(): ) token = AccessTokenEntity( identifier=TokenIdentifier.generate(), - expiration=datetime.utcnow(), + expiration=Timestamp.create_now(), user_account=account, ) diff --git a/backend/src/tests/modules/identity/user_recoveries/test_user_recovery_db_repository.py b/backend/src/tests/modules/identity/user_recoveries/test_user_recovery_db_repository.py index b1ae88ebf..912097e8f 100644 --- a/backend/src/tests/modules/identity/user_recoveries/test_user_recovery_db_repository.py +++ b/backend/src/tests/modules/identity/user_recoveries/test_user_recovery_db_repository.py @@ -1,7 +1,5 @@ """Module that defines tests for user recovery database.""" -from datetime import datetime - import pytest from kwai.core.db.database import Database @@ -31,7 +29,7 @@ async def user_recovery( ) -> UserRecoveryEntity: """Fixture for creating a user recovery entity.""" user_recovery = UserRecoveryEntity( - expiration=Timestamp(timestamp=datetime.utcnow()), + expiration=Timestamp.create_now(), user=user, ) return await repo.create(user_recovery) diff --git a/backend/src/tests/modules/identity/user_recoveries/test_user_recovery_mailer.py b/backend/src/tests/modules/identity/user_recoveries/test_user_recovery_mailer.py index bb36356aa..c2fa072af 100644 --- a/backend/src/tests/modules/identity/user_recoveries/test_user_recovery_mailer.py +++ b/backend/src/tests/modules/identity/user_recoveries/test_user_recovery_mailer.py @@ -1,7 +1,5 @@ """Module with tests for the user recovery mailer.""" -from datetime import datetime - import pytest from kwai.core.domain.value_objects.email_address import EmailAddress @@ -23,7 +21,7 @@ def user_recovery() -> UserRecoveryEntity: """Fixture creating a user recovery entity.""" return UserRecoveryEntity( - expiration=Timestamp(timestamp=datetime.utcnow()), + expiration=Timestamp.create_now(), user=UserEntity( email=EmailAddress("jigoro.kano@kwai.com"), name=Name(first_name="Jigoro", last_name="Kano"), diff --git a/backend/src/tests/modules/teams/__init__.py b/backend/src/tests/modules/teams/__init__.py new file mode 100644 index 000000000..f2ba449e1 --- /dev/null +++ b/backend/src/tests/modules/teams/__init__.py @@ -0,0 +1 @@ +"""Package for testing the teams module.""" diff --git a/backend/src/tests/modules/teams/conftest.py b/backend/src/tests/modules/teams/conftest.py new file mode 100644 index 000000000..ce1a6084e --- /dev/null +++ b/backend/src/tests/modules/teams/conftest.py @@ -0,0 +1,36 @@ +"""Module for common fixtures used for testing code of the club module.""" + +import pytest + +from kwai.core.domain.presenter import Presenter +from kwai.modules.teams.domain.team import TeamEntity +from tests.fixtures.club.coaches import * # noqa +from tests.fixtures.club.contacts import * # noqa +from tests.fixtures.club.countries import * # noqa +from tests.fixtures.club.members import * # noqa +from tests.fixtures.club.persons import * # noqa +from tests.fixtures.teams.team_members import * # noqa +from tests.fixtures.teams.teams import * # noqa + + +class DummyPresenter(Presenter[TeamEntity]): + """A dummy presenter for checking the use case result.""" + + def __init__(self): + super().__init__() + self._entity = None + + @property + def entity(self): + """Return the entity.""" + return self._entity + + def present(self, use_case_result: TeamEntity) -> None: + """Process the result of the use case.""" + self._entity = use_case_result + + +@pytest.fixture +def team_presenter() -> DummyPresenter: + """A fixture for a team presenter.""" + return DummyPresenter() diff --git a/backend/src/tests/modules/teams/domain/__init__.py b/backend/src/tests/modules/teams/domain/__init__.py new file mode 100644 index 000000000..216cf9d5b --- /dev/null +++ b/backend/src/tests/modules/teams/domain/__init__.py @@ -0,0 +1 @@ +"""Package for testing teams domain models.""" diff --git a/backend/src/tests/modules/teams/repositories/__init__.py b/backend/src/tests/modules/teams/repositories/__init__.py new file mode 100644 index 000000000..2dde9a550 --- /dev/null +++ b/backend/src/tests/modules/teams/repositories/__init__.py @@ -0,0 +1 @@ +"""Package for testing the repositories of the teams module.""" diff --git a/backend/src/tests/modules/teams/repositories/test_member_db_query.py b/backend/src/tests/modules/teams/repositories/test_member_db_query.py new file mode 100644 index 000000000..5b00e7704 --- /dev/null +++ b/backend/src/tests/modules/teams/repositories/test_member_db_query.py @@ -0,0 +1,73 @@ +"""Module for testing the team member query for a database.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.core.domain.value_objects.date import Date +from kwai.core.domain.value_objects.unique_id import UniqueId +from kwai.modules.teams.domain.team import TeamIdentifier +from kwai.modules.teams.domain.team_member import MemberIdentifier +from kwai.modules.teams.repositories.member_db_repository import MemberDbQuery +from kwai.modules.teams.repositories.member_repository import MemberQuery + +pytestmark = pytest.mark.db + + +@pytest.fixture +def query(database: Database) -> MemberQuery: + """A fixture for a team member query.""" + return MemberDbQuery(database) + + +async def test_filter_by_id(query: MemberQuery): + """Test filtering by id.""" + query.filter_by_id(MemberIdentifier(1)) + try: + await query.fetch_one() + except Exception as exc: + pytest.fail(f"An exception occurred: {exc}") + + +async def test_filter_by_uuid(query: MemberQuery): + """Test filtering by uuid.""" + query.filter_by_uuid(UniqueId.generate()) + try: + await query.fetch_one() + except Exception as exc: + pytest.fail(f"An exception occurred: {exc}") + + +async def test_filter_by_birthdate_without_end_date(query: MemberQuery): + """Test filtering by birthdate.""" + query.filter_by_birthdate(Date.create(2015, 1, 1)) + try: + await query.fetch_one() + except Exception as exc: + pytest.fail(f"An exception occurred: {exc}") + + +async def test_filter_by_birthdate(query: MemberQuery): + """Test filtering by birthdate between two dates.""" + query.filter_by_birthdate(Date.create(2015, 1, 1), Date.create(2015, 1, 31)) + try: + await query.fetch_one() + except Exception as exc: + pytest.fail(f"An exception occurred: {exc}") + + +async def test_filter_by_team(query: MemberQuery): + """Test filtering by not part of the team.""" + query.filter_by_team(TeamIdentifier(1)) + try: + await query.fetch_one() + except Exception as exc: + pytest.fail(f"An exception occurred: {exc}") + + +async def test_filter_by_not_in_team(query: MemberQuery): + """Test filtering by not part of the team.""" + query.filter_by_team(TeamIdentifier(1)) + try: + await query.fetch_one() + except Exception as exc: + pytest.fail(f"An exception occurred: {exc}") diff --git a/backend/src/tests/modules/teams/repositories/test_member_db_repository.py b/backend/src/tests/modules/teams/repositories/test_member_db_repository.py new file mode 100644 index 000000000..8826da3c4 --- /dev/null +++ b/backend/src/tests/modules/teams/repositories/test_member_db_repository.py @@ -0,0 +1,94 @@ +"""Module for testing the team member repository for a database.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.core.domain.value_objects.date import Date +from kwai.modules.club.domain.value_objects import Birthdate +from kwai.modules.teams.repositories.member_db_repository import ( + MemberDbRepository, +) + +pytestmark = pytest.mark.db + + +async def test_get_all(database: Database, make_member_in_db): + """Test getting all members.""" + member = await make_member_in_db() + repo = MemberDbRepository(database) + members = {member.id: member async for member in repo.get_all()} + assert members is not None + assert member.id in members, "The member should be returned." + + +async def test_get_by_id(database: Database, make_member_in_db): + """Test get member by its ids.""" + member = await make_member_in_db() + repo = MemberDbRepository(database) + query = repo.create_query() + query.filter_by_id(member.id) + member = await repo.get(query) + assert member is not None + + +async def test_get_by_birthdate( + database: Database, + make_member, + make_member_in_db, + make_person_in_db, + make_person, + make_contact_in_db, + make_country_in_db, + country_japan, +): + """Test get a member by its birthdate.""" + birthdate = Birthdate(Date.create(year=2000, month=12, day=31)) + await make_member_in_db( + make_member( + person=await make_person_in_db( + make_person( + birthdate=birthdate, + contact=await make_contact_in_db(), + nationality=await make_country_in_db(country_japan), + ) + ) + ) + ) + + repo = MemberDbRepository(database) + query = repo.create_query() + query.filter_by_birthdate(birthdate.date) + member = await repo.get(query) + assert member is not None + + +async def test_get_by_birthdate_between_dates( + database: Database, + make_member, + make_member_in_db, + make_person_in_db, + make_person, + make_contact_in_db, + make_country_in_db, + country_japan, +): + """Test get a member by its birthdate between two dates.""" + birthdate = Birthdate(Date.create(year=1990, month=1, day=1)) + await make_member_in_db( + make_member( + person=await make_person_in_db( + make_person( + birthdate=birthdate, + contact=await make_contact_in_db(), + nationality=await make_country_in_db(country_japan), + ) + ) + ) + ) + repo = MemberDbRepository(database) + query = repo.create_query() + start_date = Date.create(year=1990, month=1, day=1) + end_date = Date.create(year=1990, month=12, day=31) + query.filter_by_birthdate(start_date, end_date) + member = await repo.get(query) + assert member is not None diff --git a/backend/src/tests/modules/teams/repositories/test_team_db_repository.py b/backend/src/tests/modules/teams/repositories/test_team_db_repository.py new file mode 100644 index 000000000..ec5120ede --- /dev/null +++ b/backend/src/tests/modules/teams/repositories/test_team_db_repository.py @@ -0,0 +1,64 @@ +"""Module for testing the team db repository.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.core.domain.entity import Entity +from kwai.modules.teams.repositories.team_db_repository import TeamDbRepository +from kwai.modules.teams.repositories.team_repository import TeamNotFoundException + +pytestmark = pytest.mark.db + + +async def test_create_team(make_team_in_db): + """Test creating a team in the database.""" + team = await make_team_in_db() + assert team is not None, "There should be a team in the database." + + +async def test_get_team(database: Database, make_team_in_db): + """Test getting a team from the database.""" + team = await make_team_in_db() + repo = TeamDbRepository(database) + team = await repo.get(repo.create_query().filter_by_id(team.id)) + assert team is not None, "There should be a team in the database." + + +async def test_get_all_teams(database: Database): + """Test getting all teams in the database.""" + teams_iterator = TeamDbRepository(database).get_all() + assert teams_iterator is not None, "There should be a team in the database." + assert ( + await anext(teams_iterator) is not None + ), "There should be a team in the database." + + +async def test_delete_team(database: Database, make_team_in_db): + """Test deleting a team in the database.""" + team_repo = TeamDbRepository(database) + team = await make_team_in_db() + await team_repo.delete(team) + + with pytest.raises(TeamNotFoundException): + await team_repo.get(team_repo.create_query().filter_by_id(team.id)) + + +async def test_update_team(database: Database, make_team_in_db): + """Test updating a team in the database.""" + team_repo = TeamDbRepository(database) + team = await make_team_in_db() + + team = Entity.replace(team, remark="This is a test.") + await team_repo.update(team) + + team = await team_repo.get(team_repo.create_query().filter_by_id(team.id)) + assert team.remark == "This is a test.", "The team should be updated." + + +async def test_add_team_member(database: Database, make_team_in_db, make_team_member): + """Test adding a team member to a team.""" + team_repo = TeamDbRepository(database) + team = await make_team_in_db() + team_member = make_team_member() + + await team_repo.add_team_member(team, team_member) diff --git a/backend/src/tests/modules/teams/repositories/test_team_member_db_query.py b/backend/src/tests/modules/teams/repositories/test_team_member_db_query.py new file mode 100644 index 000000000..c4884bd1a --- /dev/null +++ b/backend/src/tests/modules/teams/repositories/test_team_member_db_query.py @@ -0,0 +1,22 @@ +"""Module for testing the TeamMemberDbQuery class.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.modules.teams.domain.team import TeamIdentifier +from kwai.modules.teams.repositories.team_member_db_query import TeamMemberDbQuery + + +@pytest.fixture +def query(database: Database) -> TeamMemberDbQuery: + """A fixture for a team member database query.""" + return TeamMemberDbQuery(database) + + +async def test_filter_by_teams(query: TeamMemberDbQuery): + """Test filter by teams.""" + query.filter_by_teams(TeamIdentifier(1)) + try: + await query.fetch_team_members() + except Exception as exc: + pytest.fail(f"An exception occurred: f{exc}") diff --git a/backend/src/tests/modules/teams/test_create_team.py b/backend/src/tests/modules/teams/test_create_team.py new file mode 100644 index 000000000..a92f74c68 --- /dev/null +++ b/backend/src/tests/modules/teams/test_create_team.py @@ -0,0 +1,21 @@ +"""Module that tests the Create Team use case.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.modules.teams.create_team import CreateTeam, CreateTeamCommand +from kwai.modules.teams.repositories.team_db_repository import TeamDbRepository + +pytestmark = pytest.mark.db + + +async def test_create_team(database: Database, make_team, team_presenter) -> None: + """Test the use case 'Create Team'.""" + team = make_team() + command = CreateTeamCommand( + name=team.name, + active=team.is_active, + remark=team.remark, + ) + await CreateTeam(TeamDbRepository(database), team_presenter).execute((command)) + assert team_presenter.entity is not None, "The team should be created" diff --git a/backend/src/tests/modules/teams/test_create_team_member.py b/backend/src/tests/modules/teams/test_create_team_member.py new file mode 100644 index 000000000..90aca808b --- /dev/null +++ b/backend/src/tests/modules/teams/test_create_team_member.py @@ -0,0 +1,58 @@ +"""Module for testing the use case 'Create Team Member.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.core.domain.presenter import Presenter +from kwai.modules.teams.create_team_member import ( + CreateTeamMember, + CreateTeamMemberCommand, +) +from kwai.modules.teams.domain.team import TeamEntity +from kwai.modules.teams.domain.team_member import TeamMember +from kwai.modules.teams.repositories.member_db_repository import MemberDbRepository +from kwai.modules.teams.repositories.team_db_repository import TeamDbRepository + +pytestmark = pytest.mark.db + + +class DummyPresenter(Presenter[tuple[TeamMember, TeamEntity]]): + """A dummy presenter for checking the use case result.""" + + def __init__(self): + super().__init__() + self._team_member = None + self._team = None + + @property + def team(self) -> TeamEntity: + """Return the team entity.""" + return self._team + + @property + def team_member(self) -> TeamMember: + """Return the team member.""" + return self._team_member + + def present(self, use_case_result: tuple[TeamMember, TeamEntity]) -> None: + """Handle use case result.""" + self._team_member = use_case_result[0] + self._team = use_case_result[1] + + +async def test_create_team_member( + database: Database, make_team_in_db, make_team_member_in_db +) -> None: + """Test the use case 'Create Team Member'.""" + presenter = DummyPresenter() + team = await make_team_in_db() + team_member = await make_team_member_in_db() + + command = CreateTeamMemberCommand( + team_id=team.id.value, member_id=str(team_member.member.uuid) + ) + await CreateTeamMember( + TeamDbRepository(database), MemberDbRepository(database), presenter + ).execute(command) + assert presenter.team is not None, "The team should be available" + assert presenter.team_member is not None, "There should be a member" diff --git a/backend/src/tests/modules/teams/test_delete_team.py b/backend/src/tests/modules/teams/test_delete_team.py new file mode 100644 index 000000000..0c9a61857 --- /dev/null +++ b/backend/src/tests/modules/teams/test_delete_team.py @@ -0,0 +1,21 @@ +"""Module for testing the Delete Team use case.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.modules.teams.delete_team import DeleteTeam, DeleteTeamCommand +from kwai.modules.teams.repositories.team_db_repository import TeamDbRepository +from kwai.modules.teams.repositories.team_repository import TeamNotFoundException + +pytestmark = pytest.mark.db + + +async def test_delete_team(database: Database, make_team_in_db): + """Test deleting a team.""" + team = await make_team_in_db() + command = DeleteTeamCommand(id=team.id.value) + team_repo = TeamDbRepository(database) + await DeleteTeam(team_repo).execute(command) + + with pytest.raises(TeamNotFoundException): + await team_repo.get(team_repo.create_query().filter_by_id(team.id)) diff --git a/backend/src/tests/modules/teams/test_get_members.py b/backend/src/tests/modules/teams/test_get_members.py new file mode 100644 index 000000000..077d4829e --- /dev/null +++ b/backend/src/tests/modules/teams/test_get_members.py @@ -0,0 +1,61 @@ +"""Module for testing the use case 'Get Team Members'.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.core.domain.presenter import AsyncPresenter, IterableResult +from kwai.modules.teams.domain.team_member import MemberEntity +from kwai.modules.teams.get_members import GetMembers, GetMembersCommand +from kwai.modules.teams.repositories.member_db_repository import MemberDbRepository + +pytestmark = pytest.mark.db + + +class DummyPresenter(AsyncPresenter[IterableResult[MemberEntity]]): + """A dummy presenter for checking the use case result.""" + + def __init__(self): + super().__init__() + self._count = 0 + + @property + def count(self): + """Return the count.""" + return self._count + + async def present(self, use_case_result: IterableResult[MemberEntity]) -> None: + """Count the number of members.""" + async for _ in use_case_result.iterator: + self._count += 1 + + +@pytest.fixture +def team_member_presenter() -> DummyPresenter: + """A fixture for a team member presenter.""" + return DummyPresenter() + + +async def test_get_members_not_in_team( + database: Database, make_team_in_db, make_member_in_db, team_member_presenter +): + """Test get team members.""" + team = await make_team_in_db() + await make_member_in_db() + command = GetMembersCommand(team_id=team.id.value, in_team=False) + await GetMembers(MemberDbRepository(database), team_member_presenter).execute( + command + ) + assert team_member_presenter.count > 0 + + +async def test_get_members_in_team( + database: Database, make_team_in_db, make_team_member_in_db, team_member_presenter +): + """Test get team members from a team.""" + team = await make_team_in_db() + await make_team_member_in_db(team=team) + command = GetMembersCommand(team_id=team.id.value) + await GetMembers(MemberDbRepository(database), team_member_presenter).execute( + command + ) + assert team_member_presenter.count == 1 diff --git a/backend/src/tests/modules/teams/test_get_team.py b/backend/src/tests/modules/teams/test_get_team.py new file mode 100644 index 000000000..e8c82800a --- /dev/null +++ b/backend/src/tests/modules/teams/test_get_team.py @@ -0,0 +1,18 @@ +"""Module for defining tests for the use case 'Get Teams'.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.modules.teams.get_team import GetTeam, GetTeamCommand +from kwai.modules.teams.repositories.team_db_repository import TeamDbRepository + +pytestmark = pytest.mark.db + + +async def test_get_teams(database: Database, make_team_in_db, team_presenter): + """Test get teams.""" + team = await make_team_in_db() + command = GetTeamCommand(id=team.id.value) + await GetTeam(TeamDbRepository(database), team_presenter).execute(command) + assert team_presenter.entity is not None, "The team should exist" + assert team_presenter.entity.id == team.id, "The team should be found" diff --git a/backend/src/tests/modules/teams/test_get_teams.py b/backend/src/tests/modules/teams/test_get_teams.py new file mode 100644 index 000000000..bccef39b0 --- /dev/null +++ b/backend/src/tests/modules/teams/test_get_teams.py @@ -0,0 +1,39 @@ +"""Module for defining tests for the use case 'Get Teams'.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.core.domain.presenter import AsyncPresenter, IterableResult +from kwai.modules.teams.domain.team import TeamEntity +from kwai.modules.teams.get_teams import GetTeams, GetTeamsCommand +from kwai.modules.teams.repositories.team_db_repository import TeamDbRepository + +pytestmark = pytest.mark.db + + +class DummyPresenter(AsyncPresenter[IterableResult[TeamEntity]]): + """A dummy presenter for checking the use case result.""" + + def __init__(self): + super().__init__() + self._count = 0 + + @property + def count(self): + """Return the count.""" + return self._count + + async def present(self, use_case_result: IterableResult[TeamEntity]) -> None: + """Count the teams.""" + async for _ in use_case_result.iterator: + self._count += 1 + + +async def test_get_teams(database: Database, make_team_in_db): + """Test get teams.""" + await make_team_in_db() + command = GetTeamsCommand() + presenter = DummyPresenter() + await GetTeams(TeamDbRepository(database), presenter).execute(command) + print(presenter.count) + assert presenter.count > 0, "There should be at least one team." diff --git a/backend/src/tests/modules/teams/test_update_team.py b/backend/src/tests/modules/teams/test_update_team.py new file mode 100644 index 000000000..5f88cce41 --- /dev/null +++ b/backend/src/tests/modules/teams/test_update_team.py @@ -0,0 +1,24 @@ +"""Module for testing the 'Update Team' use case.""" + +import pytest + +from kwai.core.db.database import Database +from kwai.modules.teams.repositories.team_db_repository import TeamDbRepository +from kwai.modules.teams.update_team import UpdateTeam, UpdateTeamCommand + +pytestmark = pytest.mark.db + + +async def test_update_team(database: Database, make_team_in_db, team_presenter): + """Test the use case 'Update Team'.""" + team = await make_team_in_db() + command = UpdateTeamCommand( + id=team.id.value, + name=team.name, + active=team.is_active, + remark="This is a test.", + ) + await UpdateTeam(TeamDbRepository(database), team_presenter).execute(command) + assert ( + team_presenter.entity.remark == "This is a test." + ), "The team should be updated." diff --git a/backend/src/tests/modules/training/coaches/test_coaches_db_repository.py b/backend/src/tests/modules/training/coaches/test_coaches_db_repository.py index aabcc80a1..402ca72ed 100644 --- a/backend/src/tests/modules/training/coaches/test_coaches_db_repository.py +++ b/backend/src/tests/modules/training/coaches/test_coaches_db_repository.py @@ -1,40 +1,38 @@ """Module for testing the coach database repository.""" + import pytest from kwai.core.db.database import Database from kwai.core.db.exceptions import QueryException -from kwai.modules.training.coaches.coach import CoachIdentifier from kwai.modules.training.coaches.coach_db_repository import CoachDbRepository -from kwai.modules.training.coaches.coach_repository import CoachNotFoundException -async def test_get_by_id(database: Database): +async def test_get_by_id(database: Database, make_coach_in_db): """Test get_by_id method.""" + coach = await make_coach_in_db() repo = CoachDbRepository(database) try: - await repo.get_by_id(CoachIdentifier(1)) - except CoachNotFoundException: - pass # Ok + await repo.get_by_id(coach.id) except QueryException as qe: pytest.fail(str(qe)) -async def test_get_by_ids(database: Database): +async def test_get_by_ids(database: Database, make_coach_in_db): """Test get_by_ids method.""" repo = CoachDbRepository(database) + coach_1 = await make_coach_in_db() + coach_2 = await make_coach_in_db() try: - { - coach.id: coach - async for coach in repo.get_by_ids(CoachIdentifier(1), CoachIdentifier(2)) - } + {coach.id: coach async for coach in repo.get_by_ids(coach_1.id, coach_2.id)} except QueryException as qe: pytest.fail(str(qe)) -async def test_get_all(database: Database): +async def test_get_all(database: Database, make_coach_in_db): """Test get_all method.""" + await make_coach_in_db() repo = CoachDbRepository(database) try: diff --git a/backend/src/tests/modules/training/conftest.py b/backend/src/tests/modules/training/conftest.py index f1384b1a4..48c653366 100644 --- a/backend/src/tests/modules/training/conftest.py +++ b/backend/src/tests/modules/training/conftest.py @@ -1,125 +1,10 @@ """Module with fixtures for the training bounded context.""" -import dataclasses -from collections import defaultdict -from datetime import datetime, time -from typing import Any - -import pytest - -from kwai.core.db.database import Database -from kwai.core.domain.value_objects.owner import Owner -from kwai.core.domain.value_objects.period import Period -from kwai.core.domain.value_objects.text import DocumentFormat, Locale, LocaleText -from kwai.core.domain.value_objects.time_period import TimePeriod -from kwai.core.domain.value_objects.timestamp import Timestamp -from kwai.core.domain.value_objects.weekday import Weekday -from kwai.modules.training.coaches.coach_tables import ( - CoachesTable, - CoachRow, - PersonRow, - PersonsTable, -) -from kwai.modules.training.teams.team_tables import TeamRow, TeamsTable -from kwai.modules.training.trainings.training import TrainingEntity -from kwai.modules.training.trainings.training_definition import TrainingDefinitionEntity - -Context = dict[str, list[Any]] - - -@pytest.fixture(scope="module") -def context() -> Context: - """A fixture for creating a context. - - This context is a dictionary for collecting data. - """ - return defaultdict(list) - - -@pytest.fixture(scope="module") -def person_row() -> PersonRow: - """Fixture for creating a person row.""" - return PersonRow(id=0, firstname="Jigoro", lastname="Kano") - - -@pytest.fixture(scope="module", autouse=True) -async def seed_persons(database: Database, person_row: PersonRow, context: Context): - """Seed the database with persons.""" - # For now, we create the query, in the future a repository from the members - # bounded context can be used. - query = database.create_query_factory().insert(PersonsTable.table_name) - person_dict = dataclasses.asdict(person_row) - del person_dict["id"] - person_dict["gender"] = 1 - person_dict["birthdate"] = datetime(year=1860, month=12, day=10) - person_dict["nationality_id"] = 1 - query.columns(*person_dict.keys()).values(*person_dict.values()) - context["persons"].append( - dataclasses.replace(person_row, id=await database.execute(query)) - ) - await database.commit() - - -@pytest.fixture(scope="module") -def coach_row(seed_persons, context: Context) -> CoachRow: - """Fixture for creating a coach row.""" - return CoachRow(id=0, person_id=context["persons"][0].id, active=True) - - -@pytest.fixture(scope="module", autouse=True) -async def seed_coaches(database: Database, coach_row: CoachRow, context: Context): - """Seed the database with coaches.""" - query = database.create_query_factory().insert(CoachesTable.table_name) - coach_dict = dataclasses.asdict(coach_row) - del coach_dict["id"] - query.columns(*coach_dict.keys()).values(*coach_dict.values()) - context["coaches"].append( - dataclasses.replace(coach_row, id=await database.execute(query)) - ) - await database.commit() - - -@pytest.fixture(scope="module", autouse=True) -async def seed_teams(database: Database, context: Context): - """Seed the database with teams.""" - query = database.create_query_factory().insert(TeamsTable.table_name) - team_row = TeamRow(id=0, name="U18") - team_dict = dataclasses.asdict(team_row) - del team_dict["id"] - query.columns(*team_dict.keys()).values(*team_dict.values()) - context["teams"].append( - dataclasses.replace(team_row, id=await database.execute(query)) - ) - await database.commit() - - -@pytest.fixture -async def training_entity(owner: Owner) -> TrainingEntity: - """A fixture for a training entity.""" - start_date = Timestamp.create_now() - training = TrainingEntity( - texts=[ - LocaleText( - locale=Locale.NL, - format=DocumentFormat.MARKDOWN, - title="Test Training", - content="This is a test training", - summary="This is a test training", - author=owner, - ) - ], - period=Period(start_date=start_date, end_date=start_date.add_delta(hours=1)), - ) - return training - - -@pytest.fixture -async def training_definition(owner: Owner) -> TrainingDefinitionEntity: - """A fixture for a training definition entity.""" - return TrainingDefinitionEntity( - name="U11 Training Monday", - description="Training for U11 on each monday", - weekday=Weekday.MONDAY, - owner=owner, - period=TimePeriod(start=time(hour=20), end=time(hour=21)), - ) +from tests.fixtures.club.coaches import * # noqa +from tests.fixtures.club.contacts import * # noqa +from tests.fixtures.club.countries import * # noqa +from tests.fixtures.club.members import * # noqa +from tests.fixtures.club.persons import * # noqa +from tests.fixtures.teams.teams import * # noqa +from tests.fixtures.training.training_definitions import * # noqa +from tests.fixtures.training.trainings import * # noqa diff --git a/backend/src/tests/modules/training/teams/test_team_db_repository.py b/backend/src/tests/modules/training/teams/test_team_db_repository.py index 68e69e9b3..d87e8b089 100644 --- a/backend/src/tests/modules/training/teams/test_team_db_repository.py +++ b/backend/src/tests/modules/training/teams/test_team_db_repository.py @@ -1,4 +1,5 @@ """Module for testing the team database repository.""" + import pytest from kwai.core.db.database import Database diff --git a/backend/src/tests/modules/training/test_create_training.py b/backend/src/tests/modules/training/test_create_training.py index 1944ed699..783651e79 100644 --- a/backend/src/tests/modules/training/test_create_training.py +++ b/backend/src/tests/modules/training/test_create_training.py @@ -6,11 +6,10 @@ from kwai.core.domain.use_case import TextCommand from kwai.core.domain.value_objects.owner import Owner from kwai.core.domain.value_objects.timestamp import Timestamp -from kwai.modules.training.coaches.coach import CoachEntity, CoachIdentifier +from kwai.modules.training.coaches.coach import CoachEntity from kwai.modules.training.coaches.coach_db_repository import CoachDbRepository from kwai.modules.training.coaches.coach_repository import CoachRepository from kwai.modules.training.create_training import CreateTraining, CreateTrainingCommand -from kwai.modules.training.teams.team import TeamEntity, TeamIdentifier from kwai.modules.training.teams.team_db_repository import TeamDbRepository from kwai.modules.training.teams.team_repository import TeamRepository from kwai.modules.training.training_command import Coach @@ -22,7 +21,6 @@ TrainingDefinitionRepository, ) from kwai.modules.training.trainings.training_repository import TrainingRepository -from tests.modules.training.conftest import Context @pytest.fixture @@ -50,25 +48,16 @@ def team_repo(database: Database) -> TeamRepository: @pytest.fixture -async def coach( - database: Database, context: Context, coach_repo: CoachRepository -) -> CoachEntity: +async def coach(make_coach_in_db) -> CoachEntity: """A fixture for a coach.""" - return await coach_repo.get_by_id(CoachIdentifier(context.get("coaches")[0].id)) + return await make_coach_in_db() @pytest.fixture -async def team( - database: Database, context: Context, team_repo: TeamRepository -) -> TeamEntity: - """A fixture for a team repository.""" - teams_iterator = team_repo.get_by_ids(TeamIdentifier(context.get("teams")[0].id)) - return await anext(teams_iterator) - - -@pytest.fixture -async def command(coach: CoachEntity, team: TeamEntity) -> CreateTrainingCommand: +async def command(make_coach_in_db, make_team_in_db) -> CreateTrainingCommand: """A fixture for a training entity.""" + coach = await make_coach_in_db() + team = await make_team_in_db() start_date = Timestamp.create_now() return CreateTrainingCommand( start_date=str(start_date), diff --git a/backend/src/tests/modules/training/test_create_training_definition.py b/backend/src/tests/modules/training/test_create_training_definition.py index c7425d4f4..43158fe8b 100644 --- a/backend/src/tests/modules/training/test_create_training_definition.py +++ b/backend/src/tests/modules/training/test_create_training_definition.py @@ -31,8 +31,9 @@ def team_repo(database: Database) -> TeamRepository: @pytest.fixture -def command(): +async def command(make_team_in_db): """A fixture for a create command.""" + team = await make_team_in_db() return CreateTrainingDefinitionCommand( name="U11 Monday Training", description="Training for U11 on Monday", @@ -43,7 +44,7 @@ def command(): active=True, location="Sports Hall", remark="Test", - team_id=None, + team_id=team.id.value, ) diff --git a/backend/src/tests/modules/training/test_delete_training.py b/backend/src/tests/modules/training/test_delete_training.py index 6434430e5..979726474 100644 --- a/backend/src/tests/modules/training/test_delete_training.py +++ b/backend/src/tests/modules/training/test_delete_training.py @@ -4,7 +4,6 @@ from kwai.core.db.database import Database from kwai.modules.training.delete_training import DeleteTraining, DeleteTrainingCommand -from kwai.modules.training.trainings.training import TrainingEntity from kwai.modules.training.trainings.training_db_repository import TrainingDbRepository from kwai.modules.training.trainings.training_repository import ( TrainingNotFoundException, @@ -18,23 +17,14 @@ def training_repo(database: Database) -> TrainingRepository: return TrainingDbRepository(database) -@pytest.fixture -async def saved_training_entity( - training_repo: TrainingRepository, training_entity: TrainingEntity -): - """A fixture for a training in the repository.""" - return await training_repo.create(training_entity) - - -async def test_delete_training( - training_repo: TrainingRepository, saved_training_entity -): +async def test_delete_training(training_repo: TrainingRepository, make_training_in_db): """Test the use case "Delete Training".""" - command = DeleteTrainingCommand(id=saved_training_entity.id.value) + training = await make_training_in_db() + command = DeleteTrainingCommand(id=training.id.value) try: await DeleteTraining(training_repo).execute(command) except TrainingNotFoundException as ex: pytest.fail(str(ex)) with pytest.raises(TrainingNotFoundException): - await training_repo.get_by_id(saved_training_entity.id) + await training_repo.get_by_id(training.id) diff --git a/backend/src/tests/modules/training/test_get_coaches.py b/backend/src/tests/modules/training/test_get_coaches.py index a1fccfad1..4bf47a502 100644 --- a/backend/src/tests/modules/training/test_get_coaches.py +++ b/backend/src/tests/modules/training/test_get_coaches.py @@ -1,12 +1,18 @@ """Module for testing the GetCoaches use case.""" + from kwai.core.db.database import Database from kwai.modules.training.coaches.coach_db_repository import CoachDbRepository from kwai.modules.training.get_coaches import GetCoaches, GetCoachesCommand -async def test_get_coaches(database: Database): +async def test_get_coaches(database: Database, make_coach_in_db): """Test the get coaches use case.""" - coach_repo = CoachDbRepository(database) + coach = await make_coach_in_db() + command = GetCoachesCommand(active=True) + coach_repo = CoachDbRepository(database) count, iterator = await GetCoaches(coach_repo).execute(command) - assert count is not None, "There should be result" + assert count > 0, "There should be at least one result" + + coaches = {coach.id: coach async for coach in iterator} + assert coach.id in coaches, "The coach should be retrieved" diff --git a/backend/src/tests/modules/training/test_get_teams.py b/backend/src/tests/modules/training/test_get_teams.py index d90d1ce4f..daef148bd 100644 --- a/backend/src/tests/modules/training/test_get_teams.py +++ b/backend/src/tests/modules/training/test_get_teams.py @@ -1,11 +1,14 @@ """Module for tests of the get teams use case.""" + from kwai.core.db.database import Database from kwai.modules.training.get_teams import GetTeams from kwai.modules.training.teams.team_db_repository import TeamDbRepository -async def test_get_teams(database: Database): +async def test_get_teams(database: Database, make_team_in_db): """Test use case get teams.""" - result = await GetTeams(TeamDbRepository(database)).execute() - assert result is not None - assert result.count > 0, "There should be a team" + team = await make_team_in_db() + count, iterator = await GetTeams(TeamDbRepository(database)).execute() + assert count > 0, "There should be a team" + teams = {team.id: team async for team in iterator} + assert team.id in teams, "The team should be in the result" diff --git a/backend/src/tests/modules/training/test_get_training.py b/backend/src/tests/modules/training/test_get_training.py index 0c61c0030..f20a228b2 100644 --- a/backend/src/tests/modules/training/test_get_training.py +++ b/backend/src/tests/modules/training/test_get_training.py @@ -1,11 +1,11 @@ """Module for testing the use case "Get Training".""" + import pytest from kwai.core.db.database import Database from kwai.modules.training.get_training import GetTraining, GetTrainingCommand from kwai.modules.training.trainings.training_db_repository import TrainingDbRepository from kwai.modules.training.trainings.training_repository import ( - TrainingNotFoundException, TrainingRepository, ) @@ -16,11 +16,9 @@ def training_repo(database: Database) -> TrainingRepository: return TrainingDbRepository(database) -async def test_get_training(training_repo: TrainingRepository): +async def test_get_training(training_repo: TrainingRepository, make_training_in_db): """Test the use case "Get Training".""" - command = GetTrainingCommand(id=1) - try: - training = await GetTraining(training_repo).execute(command) - assert training is not None, "There should be a training." - except TrainingNotFoundException: - pass + training = await make_training_in_db() + command = GetTrainingCommand(id=training.id.value) + training = await GetTraining(training_repo).execute(command) + assert training is not None, "There should be a training." diff --git a/backend/src/tests/modules/training/test_get_training_definition.py b/backend/src/tests/modules/training/test_get_training_definition.py index 059e8719b..9b3b4b8aa 100644 --- a/backend/src/tests/modules/training/test_get_training_definition.py +++ b/backend/src/tests/modules/training/test_get_training_definition.py @@ -1,4 +1,5 @@ """Module for testing the use case "Get Training Definition".""" + import pytest from kwai.core.db.database import Database @@ -6,7 +7,6 @@ GetTrainingDefinition, GetTrainingDefinitionCommand, ) -from kwai.modules.training.trainings.training_definition import TrainingDefinitionEntity from kwai.modules.training.trainings.training_definition_db_repository import ( TrainingDefinitionDbRepository, ) @@ -21,21 +21,13 @@ def training_definition_repo(database: Database) -> TrainingDefinitionRepository return TrainingDefinitionDbRepository(database) -@pytest.fixture -async def saved_training_definition( - training_definition_repo: TrainingDefinitionRepository, - training_definition: TrainingDefinitionEntity, -) -> TrainingDefinitionEntity: - """A fixture for a training definition in the database.""" - return await training_definition_repo.create(training_definition) - - async def test_get_training_definition( training_definition_repo: TrainingDefinitionRepository, - saved_training_definition: TrainingDefinitionEntity, + make_training_definition_in_db, ): """Test a successful execution of the use case.""" - command = GetTrainingDefinitionCommand(id=saved_training_definition.id.value) + definition = await make_training_definition_in_db() + command = GetTrainingDefinitionCommand(id=definition.id.value) training_definition = await GetTrainingDefinition(training_definition_repo).execute( command ) diff --git a/backend/src/tests/modules/training/test_get_training_definitions.py b/backend/src/tests/modules/training/test_get_training_definitions.py index b872a3ecf..ef8ebebad 100644 --- a/backend/src/tests/modules/training/test_get_training_definitions.py +++ b/backend/src/tests/modules/training/test_get_training_definitions.py @@ -1,5 +1,4 @@ """Module for testing the use case "Get Training Definitions".""" -from typing import AsyncIterator import pytest @@ -10,7 +9,6 @@ ) from kwai.modules.training.trainings.training_definition import ( TrainingDefinitionEntity, - TrainingDefinitionIdentifier, ) from kwai.modules.training.trainings.training_definition_db_repository import ( TrainingDefinitionDbRepository, @@ -20,14 +18,6 @@ ) -async def _find(iterator: AsyncIterator, id_: TrainingDefinitionIdentifier): - """Search for an entity with the given id.""" - async for entity in iterator: - if entity.id == id_: - return entity - return None - - @pytest.fixture(scope="module") def training_definition_repo(database: Database) -> TrainingDefinitionRepository: """A fixture for a training definition repository.""" @@ -45,14 +35,15 @@ async def saved_training_definition( async def test_get_training_definitions( training_definition_repo: TrainingDefinitionRepository, - saved_training_definition: TrainingDefinitionEntity, + make_training_definition_in_db, ): """Test a successful execution of the use case.""" + definition = await make_training_definition_in_db() command = GetTrainingDefinitionsCommand() count, iterator = await GetTrainingDefinitions(training_definition_repo).execute( command ) assert count >= 1, "There should be at least a training definition" - entity = await _find(iterator, saved_training_definition.id) - assert entity is not None, "The definition should be part of the data" + definitions = {definition.id: definition async for definition in iterator} + assert definition.id in definitions, "The definition should be part of the data" diff --git a/backend/src/tests/modules/training/test_get_trainings.py b/backend/src/tests/modules/training/test_get_trainings.py index 7ad9da7c4..521dff9c1 100644 --- a/backend/src/tests/modules/training/test_get_trainings.py +++ b/backend/src/tests/modules/training/test_get_trainings.py @@ -1,7 +1,10 @@ """Module for testing the use case "Get Trainings".""" + import pytest from kwai.core.db.database import Database +from kwai.core.domain.value_objects.period import Period +from kwai.core.domain.value_objects.timestamp import Timestamp from kwai.modules.training.coaches.coach_db_repository import CoachDbRepository from kwai.modules.training.coaches.coach_repository import CoachRepository from kwai.modules.training.get_trainings import GetTrainings, GetTrainingsCommand @@ -37,27 +40,36 @@ async def test_get_active_trainings( training_repo: TrainingRepository, coach_repo: CoachRepository, definition_repo: TrainingDefinitionRepository, + make_training_in_db, ): """Test the use case "Get Trainings".""" - command = GetTrainingsCommand(active=True, limit=10) + training = await make_training_in_db() + command = GetTrainingsCommand(active=True) count, iterator = await GetTrainings( training_repo, coach_repo, definition_repo ).execute(command) - entities = {entity.id: entity async for entity in iterator} + assert count > 0, "There should be at least one active training" - assert entities is not None, "There should be a result" + entities = {entity.id: entity async for entity in iterator} + assert training.id in entities, "The training should be returned" async def test_get_year_month_trainings( training_repo: TrainingRepository, coach_repo: CoachRepository, definition_repo: TrainingDefinitionRepository, + make_training_in_db, + make_training, ): """Test the use case "Get Trainings".""" - command = GetTrainingsCommand(limit=10, year=2023, month=1) + start_date = Timestamp.create_from_string("2024-01-01 19:00:00") + training = await make_training_in_db( + make_training(period=Period.create_from_delta(start_date, hours=2)) + ) + command = GetTrainingsCommand(limit=10, year=2024, month=1) count, iterator = await GetTrainings( training_repo, coach_repo, definition_repo ).execute(command) + assert count > 0, "There should be at least one training in 01/2023." entities = {entity.id: entity async for entity in iterator} - - assert entities is not None, "There should be a result" + assert training.id in entities, "The training should be returned in the result." diff --git a/backend/src/tests/modules/training/test_update_training.py b/backend/src/tests/modules/training/test_update_training.py index bc857841b..42b4ce277 100644 --- a/backend/src/tests/modules/training/test_update_training.py +++ b/backend/src/tests/modules/training/test_update_training.py @@ -5,17 +5,12 @@ from kwai.core.db.database import Database from kwai.core.domain.use_case import TextCommand from kwai.core.domain.value_objects.owner import Owner -from kwai.core.domain.value_objects.period import Period -from kwai.core.domain.value_objects.text import DocumentFormat, Locale, LocaleText from kwai.core.domain.value_objects.timestamp import Timestamp -from kwai.modules.training.coaches.coach import CoachEntity, CoachIdentifier from kwai.modules.training.coaches.coach_db_repository import CoachDbRepository from kwai.modules.training.coaches.coach_repository import CoachRepository -from kwai.modules.training.teams.team import TeamEntity, TeamIdentifier from kwai.modules.training.teams.team_db_repository import TeamDbRepository from kwai.modules.training.teams.team_repository import TeamRepository from kwai.modules.training.training_command import Coach -from kwai.modules.training.trainings.training import TrainingEntity from kwai.modules.training.trainings.training_db_repository import TrainingDbRepository from kwai.modules.training.trainings.training_definition_db_repository import ( TrainingDefinitionDbRepository, @@ -24,9 +19,7 @@ TrainingDefinitionRepository, ) from kwai.modules.training.trainings.training_repository import TrainingRepository -from kwai.modules.training.trainings.value_objects import TrainingCoach from kwai.modules.training.update_training import UpdateTraining, UpdateTrainingCommand -from tests.modules.training.conftest import Context @pytest.fixture @@ -53,71 +46,25 @@ def team_repo(database: Database) -> TeamRepository: return TeamDbRepository(database) -@pytest.fixture -async def coach( - database: Database, context: Context, coach_repo: CoachRepository -) -> CoachEntity: - """A fixture for a coach.""" - return await coach_repo.get_by_id(CoachIdentifier(context.get("coaches")[0].id)) - - -@pytest.fixture -async def team( - database: Database, context: Context, team_repo: TeamRepository -) -> TeamEntity: - """A fixture for a team repository.""" - teams_iterator = team_repo.get_by_ids(TeamIdentifier(context.get("teams")[0].id)) - return await anext(teams_iterator) - - -@pytest.fixture -async def training_entity( - training_repo: TrainingRepository, - coach: CoachEntity, - team: TeamEntity, - owner: Owner, -) -> TrainingEntity: - """A fixture for a training entity.""" - start_date = Timestamp.create_now() - return await training_repo.create( - TrainingEntity( - texts=[ - LocaleText( - locale=Locale.EN, - format=DocumentFormat.MARKDOWN, - title="Test training", - content="This is a test", - summary="This is a test", - author=owner, - ) - ], - coaches=[TrainingCoach(coach=coach, owner=owner)], - teams=[team], - period=Period( - start_date=start_date, end_date=start_date.add_delta(hours=1) - ), - ) - ) - - async def test_update_training( - training_entity: TrainingEntity, training_repo: TrainingRepository, definition_repo: TrainingDefinitionRepository, coach_repo: CoachRepository, team_repo: TeamRepository, + make_training_in_db, owner: Owner, ): """Test the use case "Update Training".""" + training = await make_training_in_db() start_date = Timestamp.create_now().add_delta(hours=1) end_date = start_date.add_delta(hours=1) command = UpdateTrainingCommand( - id=training_entity.id.value, + id=training.id.value, start_date=str(start_date), end_date=str(end_date), - active=training_entity.active, - cancelled=training_entity.cancelled, - location=training_entity.location, + active=training.active, + cancelled=training.cancelled, + location=training.location, texts=[ TextCommand( locale="en", @@ -130,14 +77,14 @@ async def test_update_training( remark="This is a test", coaches=[ Coach( - id=training_coach.coach.id.value, + id=training.coaches[0].coach.id.value, head=training_coach.type == 1, present=training_coach.present, payed=training_coach.payed, ) - for training_coach in training_entity.coaches + for training_coach in training.coaches ], - teams=[team.id.value for team in training_entity.teams], + teams=[team.id.value for team in training.teams], definition=None, ) @@ -146,3 +93,4 @@ async def test_update_training( ).execute(command) assert training is not None, "There should be a training" + assert training.texts[0].title == "Updated Test Training" diff --git a/backend/src/tests/modules/training/test_update_training_definition.py b/backend/src/tests/modules/training/test_update_training_definition.py index 26bc27e65..340cd71f9 100644 --- a/backend/src/tests/modules/training/test_update_training_definition.py +++ b/backend/src/tests/modules/training/test_update_training_definition.py @@ -4,11 +4,8 @@ from kwai.core.db.database import Database from kwai.core.domain.value_objects.owner import Owner -from kwai.core.domain.value_objects.time_period import TimePeriod -from kwai.core.domain.value_objects.weekday import Weekday from kwai.modules.training.teams.team_db_repository import TeamDbRepository from kwai.modules.training.teams.team_repository import TeamRepository -from kwai.modules.training.trainings.training_definition import TrainingDefinitionEntity from kwai.modules.training.trainings.training_definition_db_repository import ( TrainingDefinitionDbRepository, ) @@ -33,40 +30,24 @@ def team_repo(database: Database) -> TeamRepository: return TeamDbRepository(database) -@pytest.fixture -async def training_definition_entity( - training_definition_repo: TrainingDefinitionRepository, - owner: Owner, -) -> TrainingDefinitionEntity: - """A fixture for a training definition entity.""" - return await training_definition_repo.create( - TrainingDefinitionEntity( - name="U9 Training", - description="Test Training Definition", - weekday=Weekday.MONDAY, - period=TimePeriod.create_from_string("19:00", "20:00"), - owner=owner, - ) - ) - - async def test_update_training_definition( - training_definition_entity: TrainingDefinitionEntity, training_definition_repo: TrainingDefinitionRepository, team_repo: TeamRepository, + make_training_definition_in_db, owner: Owner, ): """Test the use case "Update Training".""" + definition = await make_training_definition_in_db() command = UpdateTrainingDefinitionCommand( - id=training_definition_entity.id.value, - name=training_definition_entity.name, - description=training_definition_entity.description, - weekday=training_definition_entity.weekday.value, + id=definition.id.value, + name=definition.name, + description=definition.description, + weekday=definition.weekday.value, start_time="20:00", end_time="21:00", timezone="Europe/Brussels", - active=training_definition_entity.active, - location=training_definition_entity.location, + active=definition.active, + location=definition.location, remark="This is an update test", team_id=None, ) diff --git a/backend/src/tests/modules/training/trainings/test_training_db_query.py b/backend/src/tests/modules/training/trainings/test_training_db_query.py index b73153c18..180514988 100644 --- a/backend/src/tests/modules/training/trainings/test_training_db_query.py +++ b/backend/src/tests/modules/training/trainings/test_training_db_query.py @@ -1,5 +1,6 @@ """Module for testing TrainingDbQuery.""" -from datetime import datetime, time, timedelta + +from datetime import time import pytest @@ -8,6 +9,7 @@ from kwai.core.domain.value_objects.name import Name from kwai.core.domain.value_objects.owner import Owner from kwai.core.domain.value_objects.time_period import TimePeriod +from kwai.core.domain.value_objects.timestamp import Timestamp from kwai.core.domain.value_objects.unique_id import UniqueId from kwai.core.domain.value_objects.weekday import Weekday from kwai.modules.training.coaches.coach import CoachEntity @@ -52,7 +54,7 @@ async def test_filter_by_year_month(database: Database): async def test_filter_by_dates(database: Database): """Test filtering on dates.""" query = TrainingDbQuery(database) - query.filter_by_dates(datetime.utcnow(), datetime.utcnow() + timedelta(days=1)) + query.filter_by_dates(Timestamp.create_now(), Timestamp.create_with_delta(days=1)) count = await query.count() assert count >= 0, "There should be 0 or more trainings." diff --git a/backend/src/tests/modules/training/trainings/test_training_db_repository.py b/backend/src/tests/modules/training/trainings/test_training_db_repository.py index cb9b7ec84..17dc29a11 100644 --- a/backend/src/tests/modules/training/trainings/test_training_db_repository.py +++ b/backend/src/tests/modules/training/trainings/test_training_db_repository.py @@ -5,25 +5,10 @@ from kwai.core.db.database import Database from kwai.core.db.exceptions import QueryException from kwai.core.domain.entity import Entity -from kwai.core.domain.value_objects.name import Name -from kwai.core.domain.value_objects.owner import Owner -from kwai.core.domain.value_objects.period import Period -from kwai.core.domain.value_objects.text import DocumentFormat, Locale, LocaleText -from kwai.modules.training.coaches.coach import CoachEntity, CoachIdentifier -from kwai.modules.training.trainings.training import TrainingEntity from kwai.modules.training.trainings.training_db_repository import TrainingDbRepository -from kwai.modules.training.trainings.training_definition import TrainingDefinitionEntity -from kwai.modules.training.trainings.training_definition_db_repository import ( - TrainingDefinitionDbRepository, -) -from kwai.modules.training.trainings.training_definition_repository import ( - TrainingDefinitionRepository, -) from kwai.modules.training.trainings.training_repository import ( TrainingRepository, ) -from kwai.modules.training.trainings.value_objects import TrainingCoach -from tests.modules.training.conftest import Context pytestmark = pytest.mark.db @@ -34,52 +19,15 @@ def repo(database: Database) -> TrainingRepository: return TrainingDbRepository(database) -@pytest.fixture(scope="module") -def training(user, context: Context, owner: Owner) -> TrainingEntity: - """A fixture for a training.""" - coach = context["coaches"][0] - person = context["persons"][0] - - text = [ - LocaleText( - locale=Locale.EN, - format=DocumentFormat.MARKDOWN, - title="Training U13", - summary="Training for U13", - content="", - author=owner, - ) - ] - return TrainingEntity( - texts=text, - period=Period.create_from_delta(hours=1), - coaches=[ - TrainingCoach( - coach=CoachEntity( - id_=CoachIdentifier(coach.id), - name=Name(first_name=person.firstname, last_name=person.lastname), - active=True, - ), - owner=owner, - remark="Test Training Coach", - ) - ], - ) - - -async def test_create( - repo: TrainingRepository, context: Context, training: TrainingEntity -): +async def test_create(make_training_in_db): """Test create a training.""" - new_training = await repo.create(training) - assert new_training is not None, "There should be a training." - context["trainings"] = [new_training] + training = await make_training_in_db() + assert training is not None, "There should be a training." -async def test_update(repo: TrainingRepository, context: Context): +async def test_update(repo: TrainingRepository, make_training_in_db): """Test update of a training.""" - assert len(context["trainings"]) > 0, "There should be a training" - training = context["trainings"][0] + training = await make_training_in_db() updated_training = Entity.replace(training, remark="This training is updated.") try: await repo.update(updated_training) @@ -87,45 +35,31 @@ async def test_update(repo: TrainingRepository, context: Context): pytest.fail(str(qe)) -async def test_get_all(repo: TrainingRepository): +async def test_get_all(repo: TrainingRepository, make_training_in_db): """Test get all trainings.""" + training = await make_training_in_db() trainings = {entity.id: entity async for entity in repo.get_all()} - assert trainings is not None, "There should be a result" + assert training.id in trainings, "The training should be returned in the list" -async def test_get_by_id(repo: TrainingRepository, context: Context): +async def test_get_by_id(repo: TrainingRepository, make_training_in_db): """Test get training by id.""" - assert len(context["trainings"]) > 0, "There should be a training" - training = context["trainings"][0] + training = await make_training_in_db() training = await repo.get_by_id(training.id) assert training is not None, "There should be a result" -async def test_delete(repo: TrainingRepository, context: Context): +async def test_delete(repo: TrainingRepository, make_training_in_db): """Test delete of a training.""" - assert len(context["trainings"]) > 0, "There should be a training" - training = context["trainings"][0] + training = await make_training_in_db() try: await repo.delete(training) except QueryException as qe: pytest.fail(str(qe)) -@pytest.fixture(scope="module") -def training_definition_repo(database: Database) -> TrainingDefinitionRepository: - """Fixture for a training definition repository.""" - return TrainingDefinitionDbRepository(database) - - -@pytest.fixture -async def saved_training_definition( - training_definition_repo: TrainingDefinitionRepository, - training_definition: TrainingDefinitionEntity, -) -> TrainingDefinitionEntity: - """A fixture for a training definition in the database.""" - return await training_definition_repo.create(training_definition) - - -async def test_reset_definition(repo: TrainingRepository, saved_training_definition): +async def test_reset_definition(database: Database, make_training_definition_in_db): """Test reset definition.""" - await repo.reset_definition(saved_training_definition, False) + definition = await make_training_definition_in_db() + repo = TrainingDbRepository(database) + await repo.reset_definition(definition, False) diff --git a/backend/src/tests/modules/training/trainings/test_training_definition_db_repository.py b/backend/src/tests/modules/training/trainings/test_training_definition_db_repository.py index c4181f600..2f687687f 100644 --- a/backend/src/tests/modules/training/trainings/test_training_definition_db_repository.py +++ b/backend/src/tests/modules/training/trainings/test_training_definition_db_repository.py @@ -3,78 +3,69 @@ import pytest from kwai.core.db.database import Database +from kwai.core.db.exceptions import QueryException from kwai.core.domain.entity import Entity -from kwai.modules.training.trainings.training_definition import ( - TrainingDefinitionEntity, -) from kwai.modules.training.trainings.training_definition_db_repository import ( TrainingDefinitionDbRepository, ) from kwai.modules.training.trainings.training_definition_repository import ( TrainingDefinitionNotFoundException, - TrainingDefinitionRepository, ) pytestmark = pytest.mark.db -@pytest.fixture(scope="module") -def repo(database: Database) -> TrainingDefinitionRepository: - """Fixture for a training definition repository.""" - return TrainingDefinitionDbRepository(database) - - -@pytest.fixture -async def saved_training_definition( - repo: TrainingDefinitionRepository, - training_definition: TrainingDefinitionEntity, -) -> TrainingDefinitionEntity: - """A fixture for a training definition in the database.""" - return await repo.create(training_definition) - - -def test_create(saved_training_definition: TrainingDefinitionEntity): +async def test_create(make_training_definition_in_db): """Test if the training definition was created.""" - assert ( - not saved_training_definition.id.is_empty() - ), "There should be a training definition created" + definition = await make_training_definition_in_db() + assert definition is not None, "There should be a training definition created" async def test_get_by_id( - repo: TrainingDefinitionRepository, - saved_training_definition: TrainingDefinitionEntity, + database: Database, + make_training_definition_in_db, ): """Test if the training definition can be found with the id.""" - entity = await repo.get_by_id(saved_training_definition.id) + repo = TrainingDefinitionDbRepository(database) + definition = await make_training_definition_in_db() + entity = await repo.get_by_id(definition.id) - assert ( - entity.id == saved_training_definition.id - ), "The training definition should be found" + assert entity.id == definition.id, "The training definition should be found" -async def test_get_all(repo: TrainingDefinitionRepository): +async def test_get_all( + database: Database, + make_training_definition_in_db, +): """Test if all training definitions can be loaded.""" + repo = TrainingDefinitionDbRepository(database) + definition = await make_training_definition_in_db() entities = {entity.id: entity async for entity in repo.get_all()} - assert entities is not None, "There should be a result" + assert definition.id in entities, "Definition should be in the list." async def test_update( - repo: TrainingDefinitionRepository, - saved_training_definition: TrainingDefinitionEntity, + database: Database, + make_training_definition_in_db, ): """Test update of training definition.""" - training_definition = Entity.replace( - saved_training_definition, remark="Training definition updated" - ) - await repo.update(training_definition) + repo = TrainingDefinitionDbRepository(database) + definition = await make_training_definition_in_db() + definition = Entity.replace(definition, remark="Training definition updated") + try: + await repo.update(definition) + except QueryException as qe: + pytest.fail(str(qe)) async def test_delete( - repo: TrainingDefinitionRepository, - saved_training_definition: TrainingDefinitionEntity, + database: Database, + make_training_definition_in_db, ): """Test if the training definition can be deleted.""" - await repo.delete(saved_training_definition) + repo = TrainingDefinitionDbRepository(database) + definition = await make_training_definition_in_db() + await repo.delete(definition) with pytest.raises(TrainingDefinitionNotFoundException): - await repo.get_by_id(saved_training_definition.id) + await repo.get_by_id(definition.id) diff --git a/backend/templates/index.jinja2 b/backend/templates/index.jinja2 new file mode 100644 index 000000000..b1d1a4483 --- /dev/null +++ b/backend/templates/index.jinja2 @@ -0,0 +1,22 @@ + +{% do vite.init("src/index.ts") %} + + + + + Portal + {% for preload in vite.get_preloads(application.url) %} + + {% endfor %} + {% for css in vite.get_css(application.url) %} + + {% endfor %} + + +
+
+ {% for js in vite.get_scripts(application.url) %} + + {% endfor %} + + diff --git a/backend/vagrant/test/Vagrant.provision.sh b/backend/vagrant/test/Vagrant.provision.sh index 5efe1d090..186829bbf 100644 --- a/backend/vagrant/test/Vagrant.provision.sh +++ b/backend/vagrant/test/Vagrant.provision.sh @@ -109,8 +109,8 @@ TEST_SCRIPT=$(cat < "$VAGRANT_HOME/kwai_test.sh" diff --git a/docs/index.md b/docs/index.md index 251462e03..82788acb3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,14 +1,21 @@ # KWAI > The sports club management system. +KWAI is a project for managing a sports club. + +!!! note + KWAI is a work in progress. The current focus is judo, therefore the name KWAI which means club in Japanese. + Our judo club is already using it for managing the website with news, pages and trainings. + +The system can be divided in two parts: a backend and a frontend. ## Backend -Unlike the [other version](https://github.com/fbraem/kwai-api) which is written in PHP, this backend is written in +Unlike the [other version](https://github.com/fbraem/kwai-api) which was written in PHP, this backend is written in Python and uses [FastAPI](https://fastapi.tiangolo.com/) as web framework to provide an API for Kwai. [Backend documentation](./kwai-backend/index.md) ## Frontend -The frontend consists of several single page applications. [Vue](https://vuejs.org) is used as JavaScript framework. +The frontend consists of several single page applications. [Vue](https://vuejs.org) is used as JavaScript framework. [Frontend documentation](./kwai-frontend/index.md) diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 5b497cb39..70641308e 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -1,3 +1,38 @@ :root { --md-primary-fg-color: rgb(220 38 38); } + +.doc-heading { + display: flex; + align-items: center; +} + +.badge { + display: inline-block; + padding: 2px 6px; + font-size: 12px; + font-weight: bold; + color: #fff; + border-radius: 2px; + text-align: center; + white-space: nowrap; + background-color: #49cc90; + text-transform: uppercase; + margin-left: 6px; +} + +.badge-post { + background-color: #49cc90; +} + +.badge-get { + background-color: #61affe; +} + +.badge-delete { + background-color: #f93e3e; +} + +.badge-patch { + background-color: #fb923c; +} diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs index fe6deb674..727bcd018 100644 --- a/frontend/.eslintrc.cjs +++ b/frontend/.eslintrc.cjs @@ -1,13 +1,13 @@ module.exports = { - root: true, - // This tells ESLint to load the config from the package `eslint-config-kwai` - extends: ['kwai'], - settings: { - next: { - rootDir: [ - 'apps/*/', - 'packages/*/' - ], - }, + root: true, + // This tells ESLint to load the config from the package `eslint-config-kwai` + extends: ['kwai'], + settings: { + next: { + rootDir: [ + 'apps/*/', + 'packages/*/', + ], }, -}; \ No newline at end of file + }, +}; diff --git a/frontend/Taskfile.yml b/frontend/Taskfile.yml new file mode 100644 index 000000000..26470522c --- /dev/null +++ b/frontend/Taskfile.yml @@ -0,0 +1,109 @@ +version: '3' + +tasks: + # Internal task to clean the dist folder of a package. + _npm_clean_package: + internal: true + requires: + vars: [PACKAGE] + cmds: + - rm -rf packages/{{.PACKAGE}}/dist + + # Internal task to run npm build for a package. + _npm_build_package: + internal: true + label: build_package_{{.PACKAGE}} + requires: + vars: [PACKAGE] + sources: + - packages/{{.PACKAGE}}/src/**/* + - packages/{{.PACKAGE}}/package.json + - packages/{{.PACKAGE}}/tailwind.config.js + generates: + - packages/{{.PACKAGE}}/dist/**/* + cmds: + - task: _npm_clean_package + vars: { PACKAGE: '{{.PACKAGE}}' } + - npm run build -w packages/{{.PACKAGE}} + + # @kwai/config package is a dependency for all other packages. + _npm_build_config_package: + internal: true + run: once + cmds: + - task: _npm_build_package + vars: { PACKAGE: 'kwai-config' } + + # Build a package. + build_package: + desc: Build a package + requires: + vars: [PACKAGE] + deps: [_npm_build_config_package] + cmds: + - task: _npm_build_package + vars: { PACKAGE: '{{.PACKAGE}}' } + + # Build all packages. + build_packages: + desc: Build all packages + run: once # When used as a dependency, one run is enough. + deps: + - task: build_package + vars: { PACKAGE: 'kwai-types' } + - task: build_package + vars: { PACKAGE: 'kwai-date' } + - task: build_package + vars: { PACKAGE: 'kwai-api' } + - task: build_package + vars: { PACKAGE: 'kwai-ui' } + + # Build and start a development server for an application. + # All packages will be built before starting the application. + dev_app: + desc: Build and start a development server for this application + requires: + vars: [APP] + deps: [build_packages] + cmds: + - npm run dev -w apps/{{.APP}} + + # Build and start a development server for all applications. + dev_apps: + desc: Build and start a development server for all applications + deps: + - task: dev_app + vars: { APP: 'auth' } + - task: dev_app + vars: { APP: 'author' } + - task: dev_app + vars: { APP: 'club' } + - task: dev_app + vars: { APP: 'coach' } + - task: dev_app + vars: { APP: 'portal' } + + # Build an application. + build_app: + desc: Build an application + requires: + vars: [APP] + deps: [build_packages] + cmds: + - rm -rf apps/{{.APP}}/dist + - npm run build -w apps/{{.APP}} + + # Build all applications. + build: + desc: Build all applications of the frontend + deps: + - task: build_app + vars: { APP: 'auth' } + - task: build_app + vars: { APP: 'author' } + - task: build_app + vars: { APP: 'club' } + - task: build_app + vars: { APP: 'coach' } + - task: build_app + vars: { APP: 'portal' } diff --git a/frontend/apps/auth/package.json b/frontend/apps/auth/package.json index 91920f85a..8fbd57a0c 100644 --- a/frontend/apps/auth/package.json +++ b/frontend/apps/auth/package.json @@ -2,12 +2,14 @@ "name": "@kwai/auth", "description": "The authentication application for kwai", "version": "1.0.0", + "type": "module", "dependencies": { "@kwai/api": "*", "@kwai/config": "*", "@kwai/ui": "*", - "@vueuse/core": "^10.9.0", + "@vueuse/core": "11.0.3", "pinia": "^2.1.7", + "tailwindcss-primeui": "^0.3.4", "vee-validate": "^4.12.6", "vue": "^3.4.25", "vue-i18n": "^9.13.1", @@ -15,12 +17,12 @@ }, "devDependencies": { "@intlify/unplugin-vue-i18n": "^1.4.0", - "@vitejs/plugin-vue": "^4.5.0", + "@vitejs/plugin-vue": "^5.2.1", "@vue/tsconfig": "^0.4.0", "autoprefixer": "^10.4.16", - "postcss": "^8.4.31", - "tailwindcss": "^3.4.3", - "vue-tsc": "^1.8.24" + "postcss": "^8.4.49", + "tailwindcss": "^3.4.15", + "vue-tsc": "^1.8.27" }, "private": true, "scripts": { diff --git a/frontend/apps/auth/postcss.config.cjs b/frontend/apps/auth/postcss.config.cjs new file mode 100644 index 000000000..f0f6868e8 --- /dev/null +++ b/frontend/apps/auth/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: [ + require('tailwindcss'), + require('autoprefixer'), + ], +}; diff --git a/frontend/apps/auth/postcss.config.js b/frontend/apps/auth/postcss.config.js deleted file mode 100644 index 12a703d90..000000000 --- a/frontend/apps/auth/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/frontend/apps/auth/src/index.css b/frontend/apps/auth/src/index.css index b5c61c956..efcef79ef 100644 --- a/frontend/apps/auth/src/index.css +++ b/frontend/apps/auth/src/index.css @@ -1,3 +1,6 @@ +@import '@root/style.css'; +@import '@kwai/ui/index.css'; + @tailwind base; @tailwind components; @tailwind utilities; diff --git a/frontend/apps/auth/src/index.ts b/frontend/apps/auth/src/index.ts index 44f4738fb..b38b0a4bb 100644 --- a/frontend/apps/auth/src/index.ts +++ b/frontend/apps/auth/src/index.ts @@ -1,7 +1,7 @@ import { createApp } from 'vue'; // Create app import App from './App.vue'; -import './index.css'; +import '@root/index.css'; // Setup i18n import { createI18n } from 'vue-i18n'; @@ -10,6 +10,8 @@ import messages from '@intlify/unplugin-vue-i18n/messages'; // Setup pinia store import { createPinia } from 'pinia'; +import { init } from '@kwai/ui'; + // Setup router import { createRouter, createWebHistory } from 'vue-router'; import { routes } from './routes'; @@ -30,5 +32,6 @@ const router = createRouter({ routes, }); app.use(router); +init(app); app.mount('#app'); diff --git a/frontend/apps/auth/src/pages/ChangePasswordPage.vue b/frontend/apps/auth/src/pages/ChangePasswordPage.vue index 7b84ccd52..3e565cdab 100644 --- a/frontend/apps/auth/src/pages/ChangePasswordPage.vue +++ b/frontend/apps/auth/src/pages/ChangePasswordPage.vue @@ -1,77 +1,6 @@ - - + + diff --git a/frontend/apps/auth/src/pages/InvitedPage.vue b/frontend/apps/auth/src/pages/InvitedPage.vue index 481db2e7c..180288744 100644 --- a/frontend/apps/auth/src/pages/InvitedPage.vue +++ b/frontend/apps/auth/src/pages/InvitedPage.vue @@ -1,3 +1,102 @@ + + - - diff --git a/frontend/apps/auth/src/pages/LoginPage.vue b/frontend/apps/auth/src/pages/LoginPage.vue index 45dfc549f..c52bce140 100644 --- a/frontend/apps/auth/src/pages/LoginPage.vue +++ b/frontend/apps/auth/src/pages/LoginPage.vue @@ -1,5 +1,5 @@ + + diff --git a/frontend/apps/auth/src/pages/ResetPasswordPage.vue b/frontend/apps/auth/src/pages/ResetPasswordPage.vue index 61d27c5c0..95a34fcf4 100644 --- a/frontend/apps/auth/src/pages/ResetPasswordPage.vue +++ b/frontend/apps/auth/src/pages/ResetPasswordPage.vue @@ -1,3 +1,91 @@ + + - - diff --git a/frontend/apps/auth/src/style.css b/frontend/apps/auth/src/style.css new file mode 100644 index 000000000..acc685709 --- /dev/null +++ b/frontend/apps/auth/src/style.css @@ -0,0 +1,75 @@ + +/* Primary and Surface Palettes */ +:root { + --p-primary-50: #fef2f2; + --p-primary-100: #fee2e2; + --p-primary-200: #fecaca; + --p-primary-300: #fca5a5; + --p-primary-400: #f87171; + --p-primary-500: #ef4444; + --p-primary-600: #dc2626; + --p-primary-700: #b91c1c; + --p-primary-800: #991b1b; + --p-primary-900: #7f1d1d; + --p-primary-950: #451a03; + --p-surface-0: #ffffff; + --p-surface-50: #fafafa; + --p-surface-100: #f4f4f5; + --p-surface-200: #e4e4e7; + --p-surface-300: #d4d4d8; + --p-surface-400: #a1a1aa; + --p-surface-500: #71717a; + --p-surface-600: #52525b; + --p-surface-700: #3f3f46; + --p-surface-800: #27272a; + --p-surface-900: #18181b; + --p-surface-950: #09090b; + --p-content-border-radius: 6px; +} + +/* Light */ +:root { + --p-primary-color: var(--p-surface-600); + --p-primary-contrast-color: var(--p-surface-0); + --p-primary-hover-color: var(--p-surface-900); + --p-primary-active-color: var(--p-primary-700); + --p-content-border-color: var(--p-surface-200); + --p-content-hover-background: var(--p-surface-100); + --p-content-hover-color: var(--p-surface-800); + --p-highlight-background: var(--p-primary-50); + --p-highlight-color: var(--p-primary-700); + --p-highlight-focus-background: var(--p-primary-100); + --p-highlight-focus-color: var(--p-primary-800); + --p-text-color: var(--p-surface-700); + --p-text-hover-color: var(--p-surface-800); + --p-text-muted-color: var(--p-surface-500); + --p-text-hover-muted-color: var(--p-surface-600); +} + +/* + * Dark Mode + * Defaults to system, change the selector to match the darkMode in tailwind.config. + * For example; + * darkMode: ['selector', '[class*="app-dark"]'] + * should be; + * :root[class="app-dark"] { +*/ +@media (prefers-color-scheme: dark) { + :root { + --p-primary-color: var(--p-primary-400); + --p-primary-contrast-color: var(--p-surface-900); + --p-primary-hover-color: var(--p-primary-300); + --p-primary-active-color: var(--p-primary-200); + --p-content-border-color: var(--p-surface-700); + --p-content-hover-background: var(--p-surface-800); + --p-content-hover-color: var(--p-surface-0); + --p-highlight-background: color-mix(in srgb, var(--p-primary-400), transparent 84%); + --p-highlight-color: rgba(255, 255, 255, 0.87); + --p-highlight-focus-background: color-mix(in srgb, var(--p-primary-400), transparent 76%); + --p-highlight-focus-color: rgba(255, 255, 255, 0.87); + --p-text-color: var(--p-surface-0); + --p-text-hover-color: var(--p-surface-0); + --p-text-muted-color: var(--p-surface-400); + --p-text-hover-muted-color: var(--p-surface-300); + } +} diff --git a/frontend/apps/auth/tailwind.config.js b/frontend/apps/auth/tailwind.config.js index f2a53ce40..a56b03390 100644 --- a/frontend/apps/auth/tailwind.config.js +++ b/frontend/apps/auth/tailwind.config.js @@ -1,12 +1,13 @@ /** @type {import('tailwindcss').Config} */ +import primeui from 'tailwindcss-primeui'; + module.exports = { content: [ - './index.html', './src/**/*.{html,js,ts,vue,jsx,tsx}', '../../packages/kwai-ui/src/**/*.{html,js,ts,vue,jsx,tsx}', ], theme: { extend: {}, }, - plugins: [], + plugins: [primeui], }; diff --git a/frontend/apps/auth/vite.config.ts b/frontend/apps/auth/vite.config.ts index aac1990b4..3fa4bea01 100644 --- a/frontend/apps/auth/vite.config.ts +++ b/frontend/apps/auth/vite.config.ts @@ -1,4 +1,4 @@ -import { defineConfig, splitVendorChunkPlugin } from 'vite'; +import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import toml from '@fbraem/rollup-plugin-toml'; import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'; @@ -21,13 +21,23 @@ const resolveTheme = (path: string) => { return original; }; -export default defineConfig(() => { +export default defineConfig(({ mode }) => { return { base: '/apps/auth/', + esbuild: { + pure: mode === 'production' ? ['console.log'] : [], + }, server: { + origin: 'http://localhost:3002', host: '0.0.0.0', port: 3002, }, + build: { + manifest: true, + rollupOptions: { + input: 'src/index.ts', + }, + }, plugins: [ vue(), toml(), @@ -35,7 +45,6 @@ export default defineConfig(() => { include: resolve(__dirname, './src/locales/**'), compositionOnly: true, }), - splitVendorChunkPlugin(), visualizer(), ], resolve: { @@ -45,6 +54,12 @@ export default defineConfig(() => { replacement: '', customResolver: resolveTheme, }, + { + find: '@kwai/ui', + replacement: mode === 'production' + ? '@kwai/ui' + : resolve(__dirname, '../../packages/kwai-ui/src/'), + }, { find: /^@root\/(.*)/, replacement: `${resolve(__dirname)}/src/$1`, diff --git a/frontend/apps/author/package.json b/frontend/apps/author/package.json index 958902293..87073403d 100644 --- a/frontend/apps/author/package.json +++ b/frontend/apps/author/package.json @@ -2,6 +2,7 @@ "name": "@kwai/author", "description": "The author application for Kwai", "version": "1.0.0", + "type": "module", "dependencies": { "@intlify/unplugin-vue-i18n": "4.0.0", "@kwai/api": "*", @@ -10,6 +11,7 @@ "@kwai/types": "*", "@kwai/ui": "*", "@tanstack/vue-query": "^5.32.0", + "tailwindcss-primeui": "^0.3.4", "vee-validate": "^4.12.6", "vue": "^3.4.25", "vue-i18n": "^9.13.1", @@ -17,12 +19,12 @@ "zod": "^3.23.4" }, "devDependencies": { - "@vitejs/plugin-vue": "^4.5.0", + "@vitejs/plugin-vue": "^5.2.1", "@vue/tsconfig": "^0.4.0", "autoprefixer": "^10.4.16", - "postcss": "^8.4.31", - "tailwindcss": "^3.4.3", - "vue-tsc": "^1.8.24" + "postcss": "^8.4.49", + "tailwindcss": "^3.4.15", + "vue-tsc": "^1.8.27" }, "private": true, "scripts": { diff --git a/frontend/apps/author/postcss.config.cjs b/frontend/apps/author/postcss.config.cjs new file mode 100644 index 000000000..f0f6868e8 --- /dev/null +++ b/frontend/apps/author/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: [ + require('tailwindcss'), + require('autoprefixer'), + ], +}; diff --git a/frontend/apps/author/postcss.config.js b/frontend/apps/author/postcss.config.js deleted file mode 100644 index 12a703d90..000000000 --- a/frontend/apps/author/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/frontend/apps/author/src/components/AuthorToolbar.vue b/frontend/apps/author/src/components/AuthorToolbar.vue index 0161ae59b..d151bde37 100644 --- a/frontend/apps/author/src/components/AuthorToolbar.vue +++ b/frontend/apps/author/src/components/AuthorToolbar.vue @@ -2,25 +2,16 @@ // eslint-disable-next-line import/no-absolute-path import logoUrl from '/logo.png'; import { website } from '@kwai/config'; -import type { MenuItem } from '@kwai/ui'; -import { ToolbarLogo, ToolbarMenu } from '@kwai/ui'; -import { useRouter } from 'vue-router'; -import { computed } from 'vue'; -import PrimaryButton from '@root/components/PrimaryButton.vue'; +import { useMenu, KwaiMenubar, KwaiButton, ToolbarLogo } from '@kwai/ui'; +import { isLoggedIn, useHttpLogout } from '@kwai/api'; -const router = useRouter(); -const menuItems = computed(() : MenuItem[] => { - const result: MenuItem[] = []; - for (const route of router.getRoutes()) { - if (route.meta.title) { - result.push({ - title: route.meta.title as string, - route, - }); - } - } - return result; -}); +const menuItems = useMenu(); + +const loggedIn = isLoggedIn; +const logout = () => { + useHttpLogout(); + window.location.reload(); +}; diff --git a/frontend/apps/author/src/components/PrimaryButton.vue b/frontend/apps/author/src/components/PrimaryButton.vue deleted file mode 100644 index fbfc30c00..000000000 --- a/frontend/apps/author/src/components/PrimaryButton.vue +++ /dev/null @@ -1,24 +0,0 @@ - - - - - diff --git a/frontend/apps/author/src/index.css b/frontend/apps/author/src/index.css index b5c61c956..efcef79ef 100644 --- a/frontend/apps/author/src/index.css +++ b/frontend/apps/author/src/index.css @@ -1,3 +1,6 @@ +@import '@root/style.css'; +@import '@kwai/ui/index.css'; + @tailwind base; @tailwind components; @tailwind utilities; diff --git a/frontend/apps/author/src/index.ts b/frontend/apps/author/src/index.ts index 89886a948..6952f0e60 100644 --- a/frontend/apps/author/src/index.ts +++ b/frontend/apps/author/src/index.ts @@ -1,16 +1,16 @@ import { createApp } from 'vue'; -import App from './App.vue'; -import './index.css'; -import '@kwai/ui/index.css'; +import App from '@root/App.vue'; +import '@root/index.css'; -import { VueQueryPlugin } from '@tanstack/vue-query'; import { createRouter, createWebHistory } from 'vue-router'; +import routes from '@root/routes'; -// Setup i18n import { createI18n } from 'vue-i18n'; import messages from '@intlify/unplugin-vue-i18n/messages'; -import routes from './routes'; +import { VueQueryPlugin } from '@tanstack/vue-query'; + +import { init } from '@kwai/ui'; const app = createApp(App); app.use(VueQueryPlugin); @@ -28,4 +28,5 @@ const router = createRouter({ }); app.use(router); +init(app); app.mount('#app'); diff --git a/frontend/apps/author/src/pages/HomePage.vue b/frontend/apps/author/src/pages/HomePage.vue index 7c9ab94c2..31675c35f 100644 --- a/frontend/apps/author/src/pages/HomePage.vue +++ b/frontend/apps/author/src/pages/HomePage.vue @@ -1,6 +1,5 @@ diff --git a/frontend/apps/author/src/pages/news/NewsPage.vue b/frontend/apps/author/src/pages/news/NewsPage.vue index 7d433ec71..1237f3ee6 100644 --- a/frontend/apps/author/src/pages/news/NewsPage.vue +++ b/frontend/apps/author/src/pages/news/NewsPage.vue @@ -8,12 +8,12 @@ import { CancelIcon, CheckIcon, EditIcon, + KwaiButton, OffsetPagination, usePagination, } from '@kwai/ui'; import { useNewsItems } from '@root/composables/useNewsItem'; -import PrimaryButton from '@root/components/PrimaryButton.vue'; import { useI18n } from 'vue-i18n'; import PromotedIcon from '@root/components/icons/PromotedIcon.vue'; @@ -37,13 +37,10 @@ const { data: newsItems } = useNewsItems({ offset, limit });

- + - + diff --git a/frontend/apps/author/src/pages/news/components/NewsForm.vue b/frontend/apps/author/src/pages/news/components/NewsForm.vue index eb1d49d58..c22f5e5e3 100644 --- a/frontend/apps/author/src/pages/news/components/NewsForm.vue +++ b/frontend/apps/author/src/pages/news/components/NewsForm.vue @@ -1,14 +1,14 @@ - - - - diff --git a/frontend/apps/club/src/components/icons/AddMemberIcon.vue b/frontend/apps/club/src/components/icons/AddMemberIcon.vue new file mode 100644 index 000000000..8945c90eb --- /dev/null +++ b/frontend/apps/club/src/components/icons/AddMemberIcon.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/frontend/apps/club/src/components/icons/MemberIcon.vue b/frontend/apps/club/src/components/icons/MemberIcon.vue new file mode 100644 index 000000000..855986afb --- /dev/null +++ b/frontend/apps/club/src/components/icons/MemberIcon.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/frontend/apps/club/src/composables/useCountry.ts b/frontend/apps/club/src/composables/useCountry.ts new file mode 100644 index 000000000..9bc6cfa95 --- /dev/null +++ b/frontend/apps/club/src/composables/useCountry.ts @@ -0,0 +1,12 @@ +import { JsonApiData } from '@kwai/api'; +import { z } from 'zod'; + +export const CountryResourceSchema = JsonApiData.extend({ + type: z.literal('countries'), + attributes: z.object({ + iso_2: z.string(), + iso_3: z.string(), + name: z.string(), + }), +}); +export type CountryResource = z.infer; diff --git a/frontend/apps/club/src/composables/useMember.e2e.test.ts b/frontend/apps/club/src/composables/useMember.e2e.test.ts new file mode 100644 index 000000000..27c3f24d7 --- /dev/null +++ b/frontend/apps/club/src/composables/useMember.e2e.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, it, vi } from 'vitest'; +import { defineComponent } from 'vue'; +import { useMembers } from '@root/composables/useMember'; +import { mount } from '@vue/test-utils'; +import { VueQueryPlugin } from '@tanstack/vue-query'; +import { useHttpLogin } from '@kwai/api'; +import * as process from 'node:process'; + +const noUser = process.env.KWAI_USER === undefined; + +describe('useMember e2e tests', () => { + it.skipIf(noUser)('can get members', async() => { + await useHttpLogin( + { + username: process.env.KWAI_USER as string, + password: process.env.KWAI_PASSWORD as string, + } + ); + + const TestComponent = defineComponent({ + setup() { + return useMembers({}); + }, + template: 'Test Component', + }); + const wrapper = mount(TestComponent, { + global: { + plugins: [VueQueryPlugin], + }, + }); + await vi.waitFor(() => { + expect(wrapper.vm.isPending).toBeFalsy(); + }, { timeout: 1000 }); + const members = wrapper.vm.data; + expect(members).toBeDefined(); + }); +}); diff --git a/frontend/apps/club/src/composables/useMember.test.ts b/frontend/apps/club/src/composables/useMember.test.ts new file mode 100644 index 000000000..b4e79359f --- /dev/null +++ b/frontend/apps/club/src/composables/useMember.test.ts @@ -0,0 +1,104 @@ +import { describe, expect, it } from 'vitest'; +import { MemberDocumentSchema } from '@root/composables/useMember'; + +const memberJson = { + data: { + type: 'members', + id: '1', + attributes: { + license_number: '123456', + license_end_date: '2024-31-01', + active: true, + competition: false, + remark: '', + }, + relationships: { + person: { + data: { + type: 'persons', + id: '1', + }, + }, + }, + }, + included: [ + { + type: 'persons', + id: '1', + attributes: { + first_name: 'Jigoro', + last_name: 'Kano', + gender: 1, + birthdate: '18', + remark: '', + }, + relationships: { + contact: { + data: { + type: 'contacts', + id: '1', + }, + }, + nationality: { + data: { + type: 'countries', + id: '1', + }, + }, + }, + }, + { + type: 'contacts', + id: '1', + attributes: { + emails: [], + tel: '', + mobile: '', + address: '', + postal_code: '', + city: '', + county: '', + remark: '', + }, + relationships: { + country: { + data: { + type: 'countries', + id: '1', + }, + }, + }, + }, + { + type: 'countries', + id: '1', + attributes: { + iso_2: 'JP', + iso_3: 'JPN', + name: 'Japan', + }, + }, + ], +}; + +const parse = (json: unknown) => { + const result = MemberDocumentSchema.safeParse(json); + if (!result.success) { + console.log(result.error); + } + return result; +}; + +describe('useMember tests', () => { + it('can handle a member document', () => { + const { data: document, success } = parse(memberJson); + expect(success).toBeTruthy(); + expect(document).toHaveProperty('data.type', 'members'); + }); + it('can handle a member array document', () => { + const { data: document, success } = parse({ data: [memberJson.data] }); + expect(success).toBeTruthy(); + expect(document!.data).toHaveLength(1); + expect(document).toHaveProperty('data.0.type', 'members'); + }); +}); diff --git a/frontend/apps/club/src/composables/useMember.ts b/frontend/apps/club/src/composables/useMember.ts index 6b47f6ada..51e40d3f1 100644 --- a/frontend/apps/club/src/composables/useMember.ts +++ b/frontend/apps/club/src/composables/useMember.ts @@ -1,50 +1,10 @@ -import type { DateType } from '@kwai/date'; +import { createDateFromString } from '@kwai/date'; import { JsonApiData, JsonApiDocument, JsonResourceIdentifier, useHttpApi } from '@kwai/api'; import { type Ref, ref, toValue } from 'vue'; import { useQuery } from '@tanstack/vue-query'; import { z } from 'zod'; -import { createDateFromString } from '@kwai/date'; - -interface Country { - iso2: string, - iso3: string, - name: string -} -interface Contact { - emails: string[], - tel: string, - mobile: string, - address: string, - postalCode: string, - city: string, - county: string, - country: Country -} - -interface Person { - firstName: string, - lastName: string, - gender: number, - birthdate: DateType, - remark: string, - contact: Contact, - nationality: Country -} - -interface License { - number: string, - end_date: DateType -} - -export interface Member { - id?: string, - license: License, - remark: string, - active: boolean, - competition: boolean, - person: Person, - new: boolean -} +import { type CountryResource, CountryResourceSchema } from '@root/composables/useCountry'; +import type { Member } from '@root/types/member'; export interface Members { meta: { count: number, offset: number, limit: number }, @@ -108,16 +68,6 @@ const ContactResourceSchema = JsonApiData.extend({ }); type ContactResource = z.infer; -const CountryResourceSchema = JsonApiData.extend({ - type: z.literal('countries'), - attributes: z.object({ - iso_2: z.string(), - iso_3: z.string(), - name: z.string(), - }), -}); -type CountryResource = z.infer; - export const MemberDocumentSchema = JsonApiDocument.extend({ data: z.union([ MemberResourceSchema, @@ -130,7 +80,10 @@ export const MemberDocumentSchema = JsonApiDocument.extend({ CountryResourceSchema, ]) ).default([]), -}).transform(doc => { +}); +type MemberDocument = z.infer; + +export const transform = (doc: MemberDocument) : Member | Members => { const mapModel = (data: MemberResource): Member => { const person = doc.included.find(included => included.type === PersonResourceSchema.shape.type.value && included.id === data.relationships.person.data.id) as PersonResource; const nationality = doc.included.find(included => included.type === CountryResourceSchema.shape.type.value && included.id === person.relationships.nationality.data.id) as CountryResource; @@ -145,7 +98,7 @@ export const MemberDocumentSchema = JsonApiDocument.extend({ remark: data.attributes.remark, license: { number: data.attributes.license_number, - end_date: createDateFromString(data.attributes.license_end_date), + endDate: createDateFromString(data.attributes.license_end_date), }, person: { birthdate: createDateFromString(person.attributes.birthdate), @@ -153,6 +106,7 @@ export const MemberDocumentSchema = JsonApiDocument.extend({ address: contact.attributes.address, city: contact.attributes.city, country: { + id: country.id as string, name: country.attributes.name, iso2: country.attributes.iso_2, iso3: country.attributes.iso_3, @@ -168,6 +122,7 @@ export const MemberDocumentSchema = JsonApiDocument.extend({ lastName: person.attributes.last_name, gender: person.attributes.gender, nationality: { + id: nationality.id as string, name: nationality.attributes.name, iso2: nationality.attributes.iso_2, iso3: nationality.attributes.iso_3, @@ -186,8 +141,7 @@ export const MemberDocumentSchema = JsonApiDocument.extend({ }; } return mapModel(doc.data); -}); -type MemberDocument = z.input; +}; const getMembers = async({ offset = null, @@ -208,7 +162,7 @@ const getMembers = async({ return api.get().json().then(json => { const result = MemberDocumentSchema.safeParse(json); if (result.success) { - return result.data as Members; + return transform(result.data) as Members; } console.log(result.error); throw result.error; diff --git a/frontend/apps/club/src/composables/useTeam.e2e.test.ts b/frontend/apps/club/src/composables/useTeam.e2e.test.ts new file mode 100644 index 000000000..2c11e7b05 --- /dev/null +++ b/frontend/apps/club/src/composables/useTeam.e2e.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, it, vi } from 'vitest'; +import { useTeam } from '@root/composables/useTeam'; +import { defineComponent, toRef } from 'vue'; +import { VueQueryPlugin } from '@tanstack/vue-query'; +import { mount } from '@vue/test-utils'; + +describe('useTeam e2e tests', () => { + it('can get a team', async() => { + const TestComponent = defineComponent({ + setup() { + return useTeam(toRef('1')); + }, + template: 'Test Component', + }); + const wrapper = mount(TestComponent, { + global: { + plugins: [VueQueryPlugin], + }, + }); + await vi.waitFor(() => { + expect(wrapper.vm.isPending).toBeFalsy(); + }, { timeout: 1000 }); + const team = wrapper.vm.data; + expect(team).toBeDefined(); + expect(team!.id).toBe('1'); + }); +}); diff --git a/frontend/apps/club/src/composables/useTeam.test.ts b/frontend/apps/club/src/composables/useTeam.test.ts new file mode 100644 index 000000000..79f26ff33 --- /dev/null +++ b/frontend/apps/club/src/composables/useTeam.test.ts @@ -0,0 +1,107 @@ +import { describe, expect, it } from 'vitest'; +import { type TeamDocument, TeamDocumentSchema, transform } from '@root/composables/useTeam'; +import type { TeamResource } from '@kwai/coach/src/composables/useTeam'; +import type { Team } from '@root/types/team'; + +const teamWithoutMembersJson = { + data: { + type: 'teams', + id: '1', + attributes: { name: 'U11', active: true, remark: '' }, + relationships: { team_members: { data: [] } }, + }, +}; + +const teamWithMembersJson = { + data: { + type: 'teams', + id: '1', + attributes: { name: 'U11', active: true, remark: '' }, + relationships: { + team_members: { + data: [ + { type: 'team_members', id: '1' }, + ], + }, + }, + }, + included: [{ + type: 'team_members', + id: '1', + attributes: { + active: true, + first_name: 'Jigoro', + last_name: 'Kano', + license_number: '1234', + license_end_date: '2025-01-31', + gender: 1, + birthdate: '1860-10-28', + }, + relationships: { + nationality: { + data: { type: 'countries', id: '1' }, + }, + }, + }, { + type: 'countries', + id: '1', + attributes: { iso_2: 'JP', iso_3: 'JPN', name: 'Japan' }, + }, + ], +}; + +const parse = (json: unknown) => { + const result = TeamDocumentSchema.safeParse(json); + if (!result.success) { + console.log(result.error); + } + return result; +}; + +describe('useTeam tests', () => { + it('can handle a team document', () => { + const { data: document, success } = parse(teamWithoutMembersJson); + + expect(success).toBeTruthy(); + expect(document).toHaveProperty('data.type', 'teams'); + expect(document).toHaveProperty('data.id', '1'); + expect(document).toHaveProperty('data.attributes.name', 'U11'); + }); + + it('can handle a team document with team members', () => { + const { data: document, success } = parse(teamWithMembersJson); + + expect(success).toBeTruthy(); + expect(document).toHaveProperty('data.type', 'teams'); + expect(document).toHaveProperty('data.id', '1'); + expect(document).toHaveProperty('data.relationships.team_members.data'); + const teamData = document!.data as TeamResource; + expect(teamData.relationships!.team_members.data).toHaveLength(1); + expect(document!.included).toHaveLength(2); + expect(document).toHaveProperty('included.0.type', 'team_members'); + expect(document).toHaveProperty('included.0.id', '1'); + expect(document).toHaveProperty('included.0.attributes.first_name', 'Jigoro'); + expect(document).toHaveProperty('included.0.attributes.last_name', 'Kano'); + }); + + it('can transform a document with a team', () => { + const { data: document } = parse(teamWithoutMembersJson); + + const team = transform(document as TeamDocument) as Team; + expect(team).not.toBeNull(); + expect(team).toHaveProperty('id', '1'); + expect(team).toHaveProperty('name', 'U11'); + expect(team.members).toHaveLength(0); + }); + + it('can transform a document with a team and members', () => { + const { data: document } = parse(teamWithMembersJson); + const team = transform(document as TeamDocument) as Team; + expect(team).not.toBeNull(); + expect(team).toHaveProperty('id', '1'); + expect(team).toHaveProperty('name', 'U11'); + expect(team).toHaveProperty('members.0.firstName', 'Jigoro'); + expect(team).toHaveProperty('members.0.lastName', 'Kano'); + expect(team).toHaveProperty('members.0.nationality.name', 'Japan'); + }); +}); diff --git a/frontend/apps/club/src/composables/useTeam.ts b/frontend/apps/club/src/composables/useTeam.ts new file mode 100644 index 000000000..7af8d2735 --- /dev/null +++ b/frontend/apps/club/src/composables/useTeam.ts @@ -0,0 +1,229 @@ +import type { Team, TeamMember } from '@root/types/team'; +import { + JsonApiData, + JsonApiDocument, + JsonResourceIdentifier, + type JsonResourceIdentifierType, + transformResourceArrayToObject, + useHttpApi, +} from '@kwai/api'; +import { z } from 'zod'; +import { type Ref, ref, toValue } from 'vue'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'; +import { CountryResourceSchema } from '@root/composables/useCountry'; +import { TeamMemberResourceSchema } from '@root/composables/useTeamMember'; +import { createDateFromString } from '@kwai/date'; + +export interface Teams { + meta: { + count: number, + offset: number, + limit: number + }, + items: Team[] +} + +const TeamResourceSchema = JsonApiData.extend({ + type: z.literal('teams'), + attributes: z.object({ + name: z.string(), + active: z.boolean(), + remark: z.string(), + }), + relationships: z.object({ + team_members: z.object({ + data: z.array(JsonResourceIdentifier).default([]), + }), + }), +}); + +type TeamResource = z.infer; + +export const TeamDocumentSchema = JsonApiDocument.extend({ + data: z.union([ + TeamResourceSchema, + z.array(TeamResourceSchema), + ]), + included: z.array(z.union([TeamMemberResourceSchema, CountryResourceSchema])).default([]), +}); +export type TeamDocument = z.infer; + +export const transform = (doc: TeamDocument) : Team | Teams => { + const included = transformResourceArrayToObject(doc.included); + const mapModel = (teamResource: TeamResource): Team => { + const teamMembers: TeamMember[] = []; + for (const teamMemberIdentifier of teamResource.relationships.team_members.data) { + const teamMember = included[teamMemberIdentifier.type][teamMemberIdentifier.id as string]; + const countryResourceId = teamMember.relationships!.nationality.data as JsonResourceIdentifierType; + const nationality = included[countryResourceId.type][countryResourceId.id as string]; + teamMembers.push( + { + id: teamMemberIdentifier.id as string, + active: teamMember.attributes.active, + firstName: teamMember.attributes.first_name, + lastName: teamMember.attributes.last_name, + license: { + number: teamMember.attributes.license_number, + endDate: createDateFromString(teamMember.attributes.license_end_date), + }, + gender: teamMember.attributes.gender, + birthdate: createDateFromString(teamMember.attributes.birthdate), + nationality: { + id: nationality.id as string, + iso2: nationality.attributes.iso_2, + iso3: nationality.attributes.iso_3, + name: nationality.attributes.name, + }, + activeInClub: teamMember.attributes.active_in_club, + } + ); + } + + return { + id: teamResource.id, + name: teamResource.attributes.name, + active: teamResource.attributes.active, + remark: teamResource.attributes.remark, + members: teamMembers, + }; + }; + if (Array.isArray(doc.data)) { + return { + meta: { + count: doc.meta?.count || 0, + offset: doc.meta?.offset || 0, + limit: doc.meta?.limit || 0, + }, + items: doc.data.map(mapModel), + }; + } + return mapModel(doc.data); +}; + +const getTeams = async({ + offset = null, + limit = null, +} : { + offset?: number | null, + limit?: number | null, +}) => { + let api = useHttpApi().url('/v1/teams'); + if (offset) { + api = api.query({ 'page[offset]': offset }); + } + if (limit) { + api = api.query({ 'page[limit]': limit }); + } + return api.get().json().then(json => { + const result = TeamDocumentSchema.safeParse(json); + if (result.success) { + return transform(result.data) as Teams; + } + console.log(result.error); + throw result.error; + }); +}; + +export const useTeams = ({ offset = ref(0), limit = ref(0) } : { offset?: Ref, limit?: Ref}) => { + const queryKey : { offset: Ref, limit: Ref } = { offset, limit }; + return useQuery({ + queryKey: ['club/teams', queryKey], + queryFn: () => getTeams({ + offset: toValue(offset), + limit: toValue(limit), + }), + }); +}; + +const getTeam = (id: string) : Promise => { + return useHttpApi() + .url(`/v1/teams/${id}`) + .get() + .json() + .then(json => { + const result = TeamDocumentSchema.safeParse(json); + if (result.success) { + return transform(result.data) as Team; + } + throw result.error; + }); +}; + +export const useTeam = (id: Ref) => { + return useQuery({ + queryKey: ['club/teams', id], + queryFn: () => getTeam(toValue(id)), + }); +}; + +const mutateTeam = (team: Team): Promise => { + const payload: TeamDocument = { + data: { + id: team.id, + type: 'teams', + attributes: { + name: team.name, + active: team.active, + remark: team.remark, + }, + relationships: { + team_members: { + data: [], + }, + }, + }, + included: [], + }; + if (team.id) { // Update + return useHttpApi() + .url(`/v1/teams/${team.id}`) + .patch(payload) + .json(json => { + const result = TeamDocumentSchema.safeParse(json); + if (result.success) { + return transform(result.data) as Team; + } + throw result.error; + }) + ; + } + // Create + return useHttpApi() + .url('/v1/teams') + .post(payload) + .json(json => { + const result = TeamDocumentSchema.safeParse(json); + if (result.success) { + return transform(result.data) as Team; + } + throw result.error; + }); +}; + +type OnSuccessCallback = () => void; +type OnSuccessAsyncCallback = () => Promise; +interface MutationOptions { + onSuccess?: OnSuccessCallback | OnSuccessAsyncCallback +} + +export const useTeamMutation = ({ onSuccess }: MutationOptions = {}) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (data: Team) => mutateTeam(data), + onSuccess: async(data: Team) => { + queryClient.setQueryData(['club/teams', data.id], data); + if (onSuccess) { + if (onSuccess.constructor.name === 'AsyncFunction') { + await onSuccess(); + } else { + onSuccess(); + } + } + }, + onSettled: () => queryClient.invalidateQueries({ + queryKey: ['club/teams'], + exact: true, + }), + }); +}; diff --git a/frontend/apps/club/src/composables/useTeamMember.e2e.test.ts b/frontend/apps/club/src/composables/useTeamMember.e2e.test.ts new file mode 100644 index 000000000..07e6115b2 --- /dev/null +++ b/frontend/apps/club/src/composables/useTeamMember.e2e.test.ts @@ -0,0 +1,26 @@ +import { defineComponent } from 'vue'; +import { mount } from '@vue/test-utils'; +import { VueQueryPlugin } from '@tanstack/vue-query'; +import { expect, vi } from 'vitest'; +import { useTeamMembers } from '@root/composables/useTeamMember'; + +describe('useTeamMembers e2e tests', () => { + it('can get team members', async() => { + const TestComponent = defineComponent({ + setup() { + return useTeamMembers({}); + }, + template: 'Test Component', + }); + const wrapper = mount(TestComponent, { + global: { + plugins: [VueQueryPlugin], + }, + }); + await vi.waitFor(() => { + expect(wrapper.vm.isPending).toBeFalsy(); + }, { timeout: 1000 }); + const teamMembers = wrapper.vm.data; + expect(teamMembers).toBeDefined(); + }); +}); diff --git a/frontend/apps/club/src/composables/useTeamMember.ts b/frontend/apps/club/src/composables/useTeamMember.ts new file mode 100644 index 000000000..9a0ba7b5d --- /dev/null +++ b/frontend/apps/club/src/composables/useTeamMember.ts @@ -0,0 +1,209 @@ +import type { TeamMember } from '@root/types/team'; +import { + JsonApiData, + JsonApiDocument, + JsonResourceIdentifier, + type JsonResourceIdentifierType, + type ResourceItems, + transformResourceArrayToObject, + useHttpApi, +} from '@kwai/api'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'; +import { z } from 'zod'; +import { CountryResourceSchema } from '@root/composables/useCountry'; +import { type Ref, ref, toValue } from 'vue'; +import { createDateFromString } from '@kwai/date'; + +export const TeamMemberResourceSchema = JsonApiData.extend({ + type: z.literal('team_members'), + attributes: z.object({ + active: z.boolean(), + first_name: z.string(), + last_name: z.string(), + license_number: z.string(), + license_end_date: z.string(), + gender: z.number(), + birthdate: z.string(), + active_in_club: z.boolean(), + }), + relationships: z.object({ + nationality: z.object({ + data: JsonResourceIdentifier, + }), + }), +}); +type TeamMemberResource = z.infer; + +export const TeamMemberDocumentSchema = JsonApiDocument.extend({ + data: z.union([ + TeamMemberResourceSchema, + z.array(TeamMemberResourceSchema), + ]), + included: z.array(CountryResourceSchema).default([]), +}); +export type TeamMemberDocument = z.infer; + +type TeamMembers = ResourceItems; + +export const transform = (doc: TeamMemberDocument) : TeamMember | TeamMembers => { + const included = transformResourceArrayToObject(doc.included); + const mapModel = (teamMemberResource: TeamMemberResource): TeamMember => { + const countryResourceId = teamMemberResource.relationships!.nationality.data as JsonResourceIdentifierType; + const nationality = included[countryResourceId.type][countryResourceId.id as string]; + return { + id: teamMemberResource.id as string, + active: teamMemberResource.attributes.active, + firstName: teamMemberResource.attributes.first_name, + lastName: teamMemberResource.attributes.last_name, + license: { + number: teamMemberResource.attributes.license_number, + endDate: createDateFromString(teamMemberResource.attributes.license_end_date), + }, + gender: teamMemberResource.attributes.gender, + birthdate: createDateFromString(teamMemberResource.attributes.birthdate), + nationality: { + id: nationality.id as string, + iso2: nationality.attributes.iso_2, + iso3: nationality.attributes.iso_3, + name: nationality.attributes.name, + }, + activeInClub: teamMemberResource.attributes.active_in_club, + }; + }; + if (Array.isArray(doc.data)) { + return { + meta: { + count: doc.meta?.count || 0, + offset: doc.meta?.offset || 0, + limit: doc.meta?.limit || 0, + }, + items: doc.data.map(mapModel), + }; + } + return mapModel(doc.data); +}; + +export interface TeamFilter { + id: string, + inTeam: boolean, +} + +const getTeamMembers = async({ + offset = null, + limit = null, + team = null, +} : { + offset?: number | null, + limit?: number | null, + team?: TeamFilter | null, +}) => { + let api = useHttpApi().url('/v1/teams/members'); + if (offset) { + api = api.query({ 'page[offset]': offset }); + } + if (limit) { + api = api.query({ 'page[limit]': limit }); + } + if (team) { + if (team.inTeam) { + api = api.query({ 'filter[team]': team.id }); + } else { + api = api.query({ 'filter[team]': `noteq:${team.id}` }); + } + } + return api + .get() + .json() + .then(json => { + const result = TeamMemberDocumentSchema.safeParse(json); + if (result.success) { + return transform(result.data) as TeamMembers; + } + throw result.error; + }); +}; + +export const useTeamMembers = ({ + offset = ref(0), + limit = ref(0), + team = ref(null), +} : { + offset?: Ref, + limit?: Ref, + team?: Ref, +}) => { + const queryKey = ['club/team_members']; + if (team.value) { + queryKey.push(team.value.id); + } + return useQuery({ + queryKey, + queryFn: () => getTeamMembers({ + offset: toValue(offset), + limit: toValue(limit), + team: toValue(team), + }), + }); +}; + +export interface TeamMemberData { + team_id: string, + member: TeamMemberDocument, +} + +const mutateAddTeamMember = (data: TeamMemberData): Promise => { + const payload = data.member; + return useHttpApi() + .url(`/v1/teams/${data.team_id}/members`) + .post(payload) + .json(json => { + const result = TeamMemberDocumentSchema.safeParse(json); + if (result.success) { + return transform(result.data) as TeamMember; + } + throw result.error; + }); +}; + +interface MutationOptions { + onSuccess?: (data: TeamMember, variables: TeamMemberData) => Promise | void +} + +export const useAddTeamMemberMutation = ({ onSuccess }: MutationOptions = {}) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (variables: TeamMemberData) => mutateAddTeamMember(variables), + onSuccess: (data: TeamMember, variables: TeamMemberData) => { + if (onSuccess) { + return onSuccess(data, variables); + } + }, + onSettled: (data, error, variables) => { + queryClient.invalidateQueries({ + queryKey: ['club/teams', variables.team_id], + exact: true, + }); + }, + }); +}; + +/** + * Returns a function that can be used to remove the team member + * from the club/team_members/ cache. + */ +export const useUpdateTeamMemberCache = () => { + const queryClient = useQueryClient(); + + return (teamMember: TeamMember, variables: TeamMemberData) => { + queryClient.setQueryData( + ['club/team_members', variables.team_id], + (oldData: ResourceItems) => { + return { + ...oldData, + items: oldData.items.filter(item => item.id !== teamMember.id), + }; + } + ); + }; +}; diff --git a/frontend/apps/club/src/index.css b/frontend/apps/club/src/index.css index b5c61c956..d9d0534e9 100644 --- a/frontend/apps/club/src/index.css +++ b/frontend/apps/club/src/index.css @@ -1,3 +1,6 @@ +@import './style.css'; +@import '@kwai/ui/index.css'; + @tailwind base; @tailwind components; @tailwind utilities; diff --git a/frontend/apps/club/src/index.ts b/frontend/apps/club/src/index.ts index 6d79d8a3a..4df7905d1 100644 --- a/frontend/apps/club/src/index.ts +++ b/frontend/apps/club/src/index.ts @@ -1,7 +1,6 @@ import { createApp } from 'vue'; import App from './App.vue'; -import './index.css'; -import '@kwai/ui/index.css'; +import '@root/index.css'; import { VueQueryPlugin } from '@tanstack/vue-query'; import { createRouter, createWebHistory } from 'vue-router'; diff --git a/frontend/apps/club/src/locales/nl.yaml b/frontend/apps/club/src/locales/nl.yaml index d91279bb5..fb1aec34b 100644 --- a/frontend/apps/club/src/locales/nl.yaml +++ b/frontend/apps/club/src/locales/nl.yaml @@ -7,7 +7,68 @@ not_allowed: Om deze applicatie te kunnen gebruiken moet je ingelogd zijn. members: title: Alle Actieve Leden + count: Er zijn {count} leden. members_upload: title: Opladen Leden description: | Via deze pagina kan u een bestand opladen met nieuwe of gewijzigde leden. + preview_description: | + Met preview kan je eerst controleren of het bestand correct verwerkt kan worden. + preview: Preview + error: + message: | + Opgelet er zijn fouten gevonden in het opgeladen bestand! + row: Rij + description: Omschrijving +teams: + title: Teams + error: Er is een fout gebeurd tijdens het ophalen van de teams. + name: Naam + remark: Opmerking + members: Leden + form: + sections: + team: + title: Team + description: De naam van het team + fields: + name: + label: Naam + placeholder: Geef een naam in + remark: + title: Opmerking + description: Een opmerking over het team. + fields: + remark: + label: Opmerking + placeholder: Geef een opmerking in + submit: + fields: + active: + label: Actief? + help: Is dit team actief? + button: + label: Bewaar + validations: + required: Dit is een verplicht veld. +team: + edit: + title: Wijzig Team + create: + title: Maak Team + members: + title: Leden + no_members: Er zijn nog geen leden in de club. + no_team_members: Dit team heeft nog geen leden. + add: Toevoegen + member_add: + title: Leden Toevoegen + birthdate: Geboortedatum + nationality: Nationaliteit + filter: + title: Filter Leden + name: Naam + age: Leeftijd + age_invalid: Geen geldige waarde + valid_license: Geldige Licentie + number_of_members: Er zijn geen leden die voldoen aan de filter. | Er is 1 lid dat voldoet aan de filter. | Er zijn {count} leden die voldoen aan de filter. diff --git a/frontend/apps/club/src/pages/members/MembersPage.vue b/frontend/apps/club/src/pages/members/MembersPage.vue index 60166e2ac..a4eac1968 100644 --- a/frontend/apps/club/src/pages/members/MembersPage.vue +++ b/frontend/apps/club/src/pages/members/MembersPage.vue @@ -6,11 +6,12 @@ import { KwaiButton, KwaiButtonGroup, } from '@kwai/ui'; -import { type Member, useMembers } from '@root/composables/useMember'; +import { useMembers } from '@root/composables/useMember'; import { computed } from 'vue'; import { useI18n } from 'vue-i18n'; import { breakpointsTailwind, useBreakpoints } from '@vueuse/core'; +import type { Member } from '@root/types/member'; const breakpoints = useBreakpoints(breakpointsTailwind); const largerThanLg = breakpoints.greater('lg'); @@ -18,6 +19,7 @@ const largerThanLg = breakpoints.greater('lg'); const { t } = useI18n({ useScope: 'global' }); const { data: members } = useMembers({}); + const sortedMembers = computed(() => { const result: Record = {}; if (!members.value) return result; @@ -49,6 +51,9 @@ const alphabet = [...Array(26)].map((_, i) => String.fromCharCode(65 + i)); {{ t('members.title') }} + + {{ t('members.count', { count: members.meta.count }) }} + diff --git a/frontend/apps/club/src/pages/members/MembersUploadPage.vue b/frontend/apps/club/src/pages/members/MembersUploadPage.vue index dc4b9210c..5721f72a4 100644 --- a/frontend/apps/club/src/pages/members/MembersUploadPage.vue +++ b/frontend/apps/club/src/pages/members/MembersUploadPage.vue @@ -6,27 +6,31 @@ import { ContainerSectionTitle, KwaiFileUpload, KwaiCheckbox, + KwaiTag, + ErrorAlert, } from '@kwai/ui'; import { type Ref, ref } from 'vue'; -import { useHttpApi } from '@kwai/api'; -import { MemberDocumentSchema, type Members } from '@root/composables/useMember'; +import { useHttpApi, type JsonApiErrorType } from '@kwai/api'; +import { MemberDocumentSchema, type Members, transform } from '@root/composables/useMember'; const { t } = useI18n({ useScope: 'global' }); const useMemberUpload = (files: File[]) => { - const members: Ref = ref(null); (async() => { const formData = new FormData(); formData.append('member_file', files[0]); await useHttpApi() .url('/v1/club/members/upload') + .query({ preview: preview.value }) .body(formData) .post() .json() .then(json => { const result = MemberDocumentSchema.safeParse(json); if (result.success) { - members.value = result.data as Members; + errors.value = result.data.errors ?? []; + count.value = result.data.meta?.count ?? 0; + members.value = transform(result.data) as Members; } else { console.log(result.error); throw result.error; @@ -39,6 +43,8 @@ const useMemberUpload = (files: File[]) => { const members = ref(); const preview: Ref = ref(true); +const errors: Ref = ref([]); +const count = ref(0); const upload = (files: File[]) => { members.value = useMemberUpload(files); @@ -46,24 +52,105 @@ const upload = (files: File[]) => { diff --git a/frontend/apps/club/src/pages/members/components/MemberCard.vue b/frontend/apps/club/src/pages/members/components/MemberCard.vue deleted file mode 100644 index f56c61349..000000000 --- a/frontend/apps/club/src/pages/members/components/MemberCard.vue +++ /dev/null @@ -1,10 +0,0 @@ - - - - - diff --git a/frontend/apps/club/src/pages/teams/TeamCreatePage.vue b/frontend/apps/club/src/pages/teams/TeamCreatePage.vue new file mode 100644 index 000000000..8a2499188 --- /dev/null +++ b/frontend/apps/club/src/pages/teams/TeamCreatePage.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/frontend/apps/club/src/pages/teams/TeamEditPage.vue b/frontend/apps/club/src/pages/teams/TeamEditPage.vue new file mode 100644 index 000000000..7eb98ccc3 --- /dev/null +++ b/frontend/apps/club/src/pages/teams/TeamEditPage.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/frontend/apps/club/src/pages/teams/TeamMembersPage.vue b/frontend/apps/club/src/pages/teams/TeamMembersPage.vue new file mode 100644 index 000000000..7972187f8 --- /dev/null +++ b/frontend/apps/club/src/pages/teams/TeamMembersPage.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/frontend/apps/club/src/pages/teams/TeamsPage.vue b/frontend/apps/club/src/pages/teams/TeamsPage.vue new file mode 100644 index 000000000..47e95739b --- /dev/null +++ b/frontend/apps/club/src/pages/teams/TeamsPage.vue @@ -0,0 +1,122 @@ + + + + + diff --git a/frontend/apps/club/src/pages/teams/components/MemberCard.vue b/frontend/apps/club/src/pages/teams/components/MemberCard.vue new file mode 100644 index 000000000..fe28c350d --- /dev/null +++ b/frontend/apps/club/src/pages/teams/components/MemberCard.vue @@ -0,0 +1,56 @@ + + + + + diff --git a/frontend/apps/club/src/pages/teams/components/TeamForm.vue b/frontend/apps/club/src/pages/teams/components/TeamForm.vue new file mode 100644 index 000000000..704de0e75 --- /dev/null +++ b/frontend/apps/club/src/pages/teams/components/TeamForm.vue @@ -0,0 +1,152 @@ + + + + + diff --git a/frontend/apps/club/src/pages/teams/components/TeamMemberAdd.vue b/frontend/apps/club/src/pages/teams/components/TeamMemberAdd.vue new file mode 100644 index 000000000..f02a46bc8 --- /dev/null +++ b/frontend/apps/club/src/pages/teams/components/TeamMemberAdd.vue @@ -0,0 +1,179 @@ + + + + + diff --git a/frontend/apps/club/src/pages/teams/components/TeamMemberButtonAdd.vue b/frontend/apps/club/src/pages/teams/components/TeamMemberButtonAdd.vue new file mode 100644 index 000000000..5efb229a9 --- /dev/null +++ b/frontend/apps/club/src/pages/teams/components/TeamMemberButtonAdd.vue @@ -0,0 +1,29 @@ + + + + + diff --git a/frontend/apps/club/src/routes.ts b/frontend/apps/club/src/routes.ts index f15f80687..8221feb8e 100644 --- a/frontend/apps/club/src/routes.ts +++ b/frontend/apps/club/src/routes.ts @@ -5,6 +5,12 @@ import NotAllowedPage from '@root/pages/not_allowed/NotAllowedPage.vue'; import MembersPage from '@root/pages/members/MembersPage.vue'; import ClubToolbar from '@root/components/ClubToolbar.vue'; import UploadMembersPage from '@root/pages/members/MembersUploadPage.vue'; +import TeamsPage from '@root/pages/teams/TeamsPage.vue'; +import TeamEditPage from '@root/pages/teams/TeamEditPage.vue'; +import TeamCreatePage from '@root/pages/teams/TeamCreatePage.vue'; +import TeamMembersPage from '@root/pages/teams/TeamMembersPage.vue'; +import TeamMemberButtonAdd from '@root/pages/teams/components/TeamMemberButtonAdd.vue'; +import TeamMemberAdd from '@root/pages/teams/components/TeamMemberAdd.vue'; const routes: RouteRecordRaw[] = [ { @@ -40,6 +46,9 @@ const routes: RouteRecordRaw[] = [ toolbar: ClubToolbar, main: MembersPage, }, + meta: { + title: 'Leden', + }, }, { name: 'club.upload', @@ -49,6 +58,62 @@ const routes: RouteRecordRaw[] = [ main: UploadMembersPage, }, }, + { + name: 'club.teams', + path: '/teams', + components: { + toolbar: ClubToolbar, + main: TeamsPage, + }, + meta: { + title: 'Teams', + }, + }, + { + name: 'club.teams.edit', + path: '/teams/edit/:id', + components: { + toolbar: ClubToolbar, + main: TeamEditPage, + }, + props: { + toolbar: false, + main: true, + }, + }, + { + name: 'club.teams.create', + path: '/teams/create', + components: { + toolbar: ClubToolbar, + main: TeamCreatePage, + }, + }, + { + path: '/teams/:id/members', + components: { + toolbar: ClubToolbar, + main: TeamMembersPage, + }, + props: { + toolbar: false, + main: true, + }, + children: [ + { + name: 'club.teams.members', + path: '', + component: TeamMemberButtonAdd, + props: true, + }, + { + name: 'club.teams.members.add', + path: 'add', + component: TeamMemberAdd, + props: true, + }, + ], + }, ], }, ]; diff --git a/frontend/apps/club/src/style.css b/frontend/apps/club/src/style.css new file mode 100644 index 000000000..a885cd482 --- /dev/null +++ b/frontend/apps/club/src/style.css @@ -0,0 +1,73 @@ +/* Primary and Surface Palettes */ +:root { + --p-primary-50: #f0fdf4; + --p-primary-100: #dcfce7; + --p-primary-200: #bbf7d0; + --p-primary-300: #86efac; + --p-primary-400: #4ade80; + --p-primary-500: #22c55e; + --p-primary-600: #16a34a; + --p-primary-700: #15803d; + --p-primary-800: #166534; + --p-primary-900: #14532d; + --p-surface-0: #ffffff; + --p-surface-50: #fafafa; + --p-surface-100: #f4f4f5; + --p-surface-200: #e4e4e7; + --p-surface-300: #d4d4d8; + --p-surface-400: #a1a1aa; + --p-surface-500: #71717a; + --p-surface-600: #52525b; + --p-surface-700: #3f3f46; + --p-surface-800: #27272a; + --p-surface-900: #18181b; + --p-surface-950: #09090b; + --p-content-border-radius: 6px; +} + +/* Light */ +:root { + --p-primary-color: var(--p-primary-500); + --p-primary-contrast-color: var(--p-surface-0); + --p-primary-hover-color: var(--p-primary-600); + --p-primary-active-color: var(--p-primary-700); + --p-content-border-color: var(--p-surface-200); + --p-content-hover-background: var(--p-surface-100); + --p-content-hover-color: var(--p-surface-800); + --p-highlight-background: var(--p-primary-50); + --p-highlight-color: var(--p-primary-700); + --p-highlight-focus-background: var(--p-primary-100); + --p-highlight-focus-color: var(--p-primary-800); + --p-text-color: var(--p-surface-700); + --p-text-hover-color: var(--p-surface-800); + --p-text-muted-color: var(--p-surface-500); + --p-text-hover-muted-color: var(--p-surface-600); +} + +/* + * Dark Mode + * Defaults to system, change the selector to match the darkMode in tailwind.config. + * For example; + * darkMode: ['selector', '[class*="app-dark"]'] + * should be; + * :root[class="app-dark"] { +*/ +@media (prefers-color-scheme: dark) { + :root { + --p-primary-color: var(--p-primary-400); + --p-primary-contrast-color: var(--p-surface-900); + --p-primary-hover-color: var(--p-primary-300); + --p-primary-active-color: var(--p-primary-200); + --p-content-border-color: var(--p-surface-700); + --p-content-hover-background: var(--p-surface-800); + --p-content-hover-color: var(--p-surface-0); + --p-highlight-background: color-mix(in srgb, var(--p-primary-400), transparent 84%); + --p-highlight-color: rgba(255, 255, 255, 0.87); + --p-highlight-focus-background: color-mix(in srgb, var(--p-primary-400), transparent 76%); + --p-highlight-focus-color: rgba(255, 255, 255, 0.87); + --p-text-color: var(--p-surface-0); + --p-text-hover-color: var(--p-surface-0); + --p-text-muted-color: var(--p-surface-400); + --p-text-hover-muted-color: var(--p-surface-300); + } +} diff --git a/frontend/apps/club/src/types/contact.ts b/frontend/apps/club/src/types/contact.ts new file mode 100644 index 000000000..9f0106505 --- /dev/null +++ b/frontend/apps/club/src/types/contact.ts @@ -0,0 +1,12 @@ +import type { Country } from './country'; + +export interface Contact { + emails: string[], + tel: string, + mobile: string, + address: string, + postalCode: string, + city: string, + county: string, + country: Country +} diff --git a/frontend/apps/club/src/types/country.ts b/frontend/apps/club/src/types/country.ts new file mode 100644 index 000000000..897963f17 --- /dev/null +++ b/frontend/apps/club/src/types/country.ts @@ -0,0 +1,6 @@ +export interface Country { + id: string, + iso2: string, + iso3: string, + name: string +} diff --git a/frontend/apps/club/src/types/member.ts b/frontend/apps/club/src/types/member.ts new file mode 100644 index 000000000..1f41251cc --- /dev/null +++ b/frontend/apps/club/src/types/member.ts @@ -0,0 +1,17 @@ +import type { DateType } from '@kwai/date'; +import type { Person } from './person'; + +export interface License { + number: string, + endDate: DateType +} + +export interface Member { + id?: string, + license: License, + remark: string, + active: boolean, + competition: boolean, + person: Person, + new: boolean +} diff --git a/frontend/apps/club/src/types/person.ts b/frontend/apps/club/src/types/person.ts new file mode 100644 index 000000000..a5a13e279 --- /dev/null +++ b/frontend/apps/club/src/types/person.ts @@ -0,0 +1,13 @@ +import type { DateType } from '@kwai/date'; +import type { Contact } from './contact'; +import type { Country } from './country'; + +export interface Person { + firstName: string, + lastName: string, + gender: number, + birthdate: DateType, + remark: string, + contact: Contact, + nationality: Country +} diff --git a/frontend/apps/club/src/types/team.ts b/frontend/apps/club/src/types/team.ts new file mode 100644 index 000000000..f1a18ced2 --- /dev/null +++ b/frontend/apps/club/src/types/team.ts @@ -0,0 +1,23 @@ +import type { License } from '@root/types/member'; +import type { Country } from '@root/types/country'; +import type { DateType } from '@kwai/date'; + +export interface TeamMember { + id: string, + active: boolean, + firstName: string, + lastName: string, + license: License, + gender: number, + birthdate: DateType, + nationality: Country, + activeInClub: boolean +} + +export interface Team { + id?: string, + name: string, + active: boolean, + remark: string, + members: TeamMember[], +} diff --git a/frontend/apps/club/tailwind.config.js b/frontend/apps/club/tailwind.config.js index 9a0d5e6a4..b2e8213e9 100644 --- a/frontend/apps/club/tailwind.config.js +++ b/frontend/apps/club/tailwind.config.js @@ -1,19 +1,14 @@ /** @type {import('tailwindcss').Config} */ -import colors from 'tailwindcss/colors'; +import primeui from 'tailwindcss-primeui'; + module.exports = { content: [ - './index.html', './src/**/*.{html,js,ts,vue,jsx,tsx}', '../../packages/kwai-ui/src/**/*.{html,js,ts,vue,jsx,tsx}', - 'node_modules/@indielayer/ui/{lib,src}/**/*', ], theme: { extend: { - colors: { - primary: colors.green, - 'primary-text': colors.white, - }, }, }, - plugins: [], + plugins: [primeui], }; diff --git a/frontend/apps/club/vite.config.ts b/frontend/apps/club/vite.config.ts index 8c732f193..8380a0f28 100644 --- a/frontend/apps/club/vite.config.ts +++ b/frontend/apps/club/vite.config.ts @@ -1,4 +1,4 @@ -import { defineConfig, splitVendorChunkPlugin } from 'vite'; +import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import { resolve } from 'path'; import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'; @@ -9,9 +9,16 @@ export default defineConfig(({ mode }) => { return { base: '/apps/club/', server: { + origin: 'http://localhost:3004', host: '0.0.0.0', port: 3004, }, + build: { + manifest: true, + rollupOptions: { + input: 'src/index.ts', + }, + }, esbuild: { pure: mode === 'production' ? ['console.log'] : [], }, @@ -21,7 +28,6 @@ export default defineConfig(({ mode }) => { include: resolve(__dirname, './src/locales/**'), compositionOnly: true, }), - splitVendorChunkPlugin(), visualizer(), ], resolve: { @@ -39,5 +45,9 @@ export default defineConfig(({ mode }) => { ], dedupe: ['vue'], }, + test: { + global: true, + environment: 'jsdom', + }, }; }); diff --git a/frontend/apps/club/vitest.config.ts b/frontend/apps/club/vitest.config.ts new file mode 100644 index 000000000..caf993c29 --- /dev/null +++ b/frontend/apps/club/vitest.config.ts @@ -0,0 +1,19 @@ +import { resolve } from 'path'; +import { loadEnv } from 'vite'; +import { defineConfig } from 'vitest/config'; + +export default defineConfig(({ mode }) => ({ + test: { + globals: true, + environment: 'jsdom', + env: loadEnv(mode, '../../', ''), + }, + resolve: { + alias: [ + { + find: /^@root\/(.*)/, + replacement: `${resolve(__dirname)}/src/$1`, + }, + ], + }, +})); diff --git a/frontend/apps/coach/package.json b/frontend/apps/coach/package.json index b10c35af7..e29573542 100644 --- a/frontend/apps/coach/package.json +++ b/frontend/apps/coach/package.json @@ -2,6 +2,7 @@ "name": "@kwai/coach", "description": "The coach application of kwai", "version": "1.0.0", + "type": "module", "dependencies": { "@intlify/unplugin-vue-i18n": "4.0.0", "@kwai/api": "*", @@ -10,8 +11,9 @@ "@kwai/types": "*", "@kwai/ui": "*", "@tanstack/vue-query": "^5.32.0", - "@vuepic/vue-datepicker": "8.4.0", - "@vueuse/core": "^10.9.0", + "@vuepic/vue-datepicker": "9.0.3", + "@vueuse/core": "11.0.3", + "tailwindcss-primeui": "^0.3.4", "vee-validate": "^4.12.6", "vue": "^3.4.25", "vue-i18n": "^9.13.1", @@ -19,12 +21,12 @@ "zod": "^3.23.4" }, "devDependencies": { - "@vitejs/plugin-vue": "^4.5.0", + "@vitejs/plugin-vue": "^5.2.1", "@vue/tsconfig": "^0.4.0", "autoprefixer": "^10.4.16", - "postcss": "^8.4.31", - "tailwindcss": "^3.4.3", - "vue-tsc": "^1.8.24" + "postcss": "^8.4.49", + "tailwindcss": "^3.4.15", + "vue-tsc": "^1.8.27" }, "scripts": { "build": "vue-tsc --noEmit && vite build --config ./vite.config.ts", diff --git a/frontend/apps/coach/postcss.config.cjs b/frontend/apps/coach/postcss.config.cjs new file mode 100644 index 000000000..f0f6868e8 --- /dev/null +++ b/frontend/apps/coach/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: [ + require('tailwindcss'), + require('autoprefixer'), + ], +}; diff --git a/frontend/apps/coach/postcss.config.js b/frontend/apps/coach/postcss.config.js deleted file mode 100644 index 12a703d90..000000000 --- a/frontend/apps/coach/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/frontend/apps/coach/src/components/CoachToolbar.vue b/frontend/apps/coach/src/components/CoachToolbar.vue index af7733a3e..bcd8b6282 100644 --- a/frontend/apps/coach/src/components/CoachToolbar.vue +++ b/frontend/apps/coach/src/components/CoachToolbar.vue @@ -1,11 +1,17 @@ diff --git a/frontend/apps/coach/src/index.css b/frontend/apps/coach/src/index.css index b5c61c956..efcef79ef 100644 --- a/frontend/apps/coach/src/index.css +++ b/frontend/apps/coach/src/index.css @@ -1,3 +1,6 @@ +@import '@root/style.css'; +@import '@kwai/ui/index.css'; + @tailwind base; @tailwind components; @tailwind utilities; diff --git a/frontend/apps/coach/src/index.ts b/frontend/apps/coach/src/index.ts index 271ef479d..6952f0e60 100644 --- a/frontend/apps/coach/src/index.ts +++ b/frontend/apps/coach/src/index.ts @@ -1,7 +1,6 @@ import { createApp } from 'vue'; import App from '@root/App.vue'; import '@root/index.css'; -import '@kwai/ui/index.css'; import { createRouter, createWebHistory } from 'vue-router'; import routes from '@root/routes'; @@ -11,6 +10,8 @@ import messages from '@intlify/unplugin-vue-i18n/messages'; import { VueQueryPlugin } from '@tanstack/vue-query'; +import { init } from '@kwai/ui'; + const app = createApp(App); app.use(VueQueryPlugin); @@ -27,4 +28,5 @@ const router = createRouter({ }); app.use(router); +init(app); app.mount('#app'); diff --git a/frontend/apps/coach/src/pages/home/HomePage.vue b/frontend/apps/coach/src/pages/home/HomePage.vue index cdd899439..e74c318d3 100644 --- a/frontend/apps/coach/src/pages/home/HomePage.vue +++ b/frontend/apps/coach/src/pages/home/HomePage.vue @@ -1,7 +1,6 @@ @@ -24,12 +23,12 @@ const { t } = useI18n({ useScope: 'global' });

diff --git a/frontend/apps/coach/src/pages/home/components/TrainingDefinitionsCard.vue b/frontend/apps/coach/src/pages/home/components/TrainingDefinitionsCard.vue index 47e919d98..fe34a4aae 100644 --- a/frontend/apps/coach/src/pages/home/components/TrainingDefinitionsCard.vue +++ b/frontend/apps/coach/src/pages/home/components/TrainingDefinitionsCard.vue @@ -1,6 +1,5 @@ @@ -17,12 +16,12 @@ const { t } = useI18n({ useScope: 'global' });

diff --git a/frontend/apps/coach/src/pages/home/components/TrainingsCard.vue b/frontend/apps/coach/src/pages/home/components/TrainingsCard.vue index e7036e8da..dbf1f90af 100644 --- a/frontend/apps/coach/src/pages/home/components/TrainingsCard.vue +++ b/frontend/apps/coach/src/pages/home/components/TrainingsCard.vue @@ -1,6 +1,5 @@ @@ -17,12 +16,12 @@ const { t } = useI18n({ useScope: 'global' });

diff --git a/frontend/apps/coach/src/pages/training_definitions/GenerateTrainingsPage.vue b/frontend/apps/coach/src/pages/training_definitions/GenerateTrainingsPage.vue index 66c46427b..bc56f8fb4 100644 --- a/frontend/apps/coach/src/pages/training_definitions/GenerateTrainingsPage.vue +++ b/frontend/apps/coach/src/pages/training_definitions/GenerateTrainingsPage.vue @@ -6,14 +6,14 @@ import { ContainerSectionBanner, ContainerSectionContent, ContainerSectionTitle, - DateRangePicker, + KwaiDateRangePicker, DeleteIcon, InfoAlert, + KwaiButton, LinkTag, NewIcon, } from '@kwai/ui'; import { useI18n } from 'vue-i18n'; -import PrimaryButton from '@root/components/PrimaryButton.vue'; import TrainingDefinitionCard from '@root/pages/training_definitions/components/TrainingDefinitionCard.vue'; import { ref, toRef } from 'vue'; import { useForm } from 'vee-validate'; @@ -94,17 +94,14 @@ const saveTrainings = () => { @@ -171,13 +168,10 @@ const saveTrainings = () => { v-if="trainings.length > 0" class="w-full flex flex-col" > - + {{ t('generate_trainings.save') }} - +
diff --git a/frontend/apps/coach/src/pages/training_definitions/TrainingDefinitionsPage.vue b/frontend/apps/coach/src/pages/training_definitions/TrainingDefinitionsPage.vue index 288135388..c2831b81b 100644 --- a/frontend/apps/coach/src/pages/training_definitions/TrainingDefinitionsPage.vue +++ b/frontend/apps/coach/src/pages/training_definitions/TrainingDefinitionsPage.vue @@ -4,11 +4,12 @@ import { ContainerSection, ContainerSectionBanner, ContainerSectionContent, - ContainerSectionTitle, EditIcon, + ContainerSectionTitle, + EditIcon, + KwaiButton, NewIcon, } from '@kwai/ui'; import { useI18n } from 'vue-i18n'; -import PrimaryButton from '@root/components/PrimaryButton.vue'; import TrainingDefinitionCard from '@root/pages/training_definitions/components/TrainingDefinitionCard.vue'; import AddCalendarIcon from '@root/components/icons/AddCalendarIcon.vue'; @@ -33,13 +34,10 @@ const { data: trainingDefinitions } = useTrainingDefinitions();

@@ -50,9 +48,8 @@ const { data: trainingDefinitions } = useTrainingDefinitions(); diff --git a/frontend/apps/coach/src/pages/training_definitions/components/TrainingDefinitionForm.vue b/frontend/apps/coach/src/pages/training_definitions/components/TrainingDefinitionForm.vue index b3346be2f..60c216970 100644 --- a/frontend/apps/coach/src/pages/training_definitions/components/TrainingDefinitionForm.vue +++ b/frontend/apps/coach/src/pages/training_definitions/components/TrainingDefinitionForm.vue @@ -5,7 +5,7 @@ import { useI18n } from 'vue-i18n'; import { useForm } from 'vee-validate'; import { - Button, + KwaiButton, CheckBox, ErrorAlert, FormSection, @@ -13,7 +13,7 @@ import { InputField, SelectOption, TextareaField, - TimePicker, + KwaiTimePicker, isStringRequired, } from '@kwai/ui'; import type { Option, TimeModel } from '@kwai/ui'; @@ -225,7 +225,7 @@ watch(definition, nv => { - { {{ t('training_definition.form.sections.period.fields.start_time.label') }} : - - + { {{ t('training_definition.form.sections.period.fields.end_time.label') }} : - + @@ -278,13 +278,12 @@ watch(definition, nv => {
- +
{{ t('training_definition.form.error') }} diff --git a/frontend/apps/coach/src/pages/trainings/TrainingsPage.vue b/frontend/apps/coach/src/pages/trainings/TrainingsPage.vue index 9e0dd4f33..6de01927a 100644 --- a/frontend/apps/coach/src/pages/trainings/TrainingsPage.vue +++ b/frontend/apps/coach/src/pages/trainings/TrainingsPage.vue @@ -12,9 +12,9 @@ import { CancelIcon, CheckIcon, EditIcon, + KwaiButton, TextBadge, } from '@kwai/ui'; -import PrimaryButton from '@root/components/PrimaryButton.vue'; import { createDate, createFromDate, now } from '@kwai/date'; import { computed, ref, watch } from 'vue'; import { useRoute, useRouter } from 'vue-router'; @@ -103,16 +103,13 @@ const setToCurrent = () => { :format="format" auto-apply /> - + - - + + {{ t('trainings.banner.button') }} - +
@@ -188,12 +185,9 @@ const setToCurrent = () => { /> - + - + diff --git a/frontend/apps/coach/src/pages/trainings/components/TrainingForm.vue b/frontend/apps/coach/src/pages/trainings/components/TrainingForm.vue index f398bf667..98926f3e4 100644 --- a/frontend/apps/coach/src/pages/trainings/components/TrainingForm.vue +++ b/frontend/apps/coach/src/pages/trainings/components/TrainingForm.vue @@ -1,12 +1,12 @@ - - - - diff --git a/frontend/apps/portal/src/components/toolbar/ToolbarUser.vue b/frontend/apps/portal/src/components/toolbar/ToolbarUser.vue index 193d17d15..d773d4570 100644 --- a/frontend/apps/portal/src/components/toolbar/ToolbarUser.vue +++ b/frontend/apps/portal/src/components/toolbar/ToolbarUser.vue @@ -1,16 +1,26 @@ diff --git a/frontend/apps/portal/src/index.css b/frontend/apps/portal/src/index.css index bd6213e1d..efcef79ef 100644 --- a/frontend/apps/portal/src/index.css +++ b/frontend/apps/portal/src/index.css @@ -1,3 +1,6 @@ +@import '@root/style.css'; +@import '@kwai/ui/index.css'; + @tailwind base; @tailwind components; -@tailwind utilities; \ No newline at end of file +@tailwind utilities; diff --git a/frontend/apps/portal/src/index.ts b/frontend/apps/portal/src/index.ts index ea40e77d9..5161feb88 100644 --- a/frontend/apps/portal/src/index.ts +++ b/frontend/apps/portal/src/index.ts @@ -1,8 +1,9 @@ import { createApp } from 'vue'; - +// Create app import App from './App.vue'; -import './index.css'; +import '@root/index.css'; +import { init } from '@kwai/ui'; import { createRouter, createWebHistory } from 'vue-router'; import routes from './routes'; import { VueQueryPlugin } from '@tanstack/vue-query'; @@ -12,7 +13,7 @@ const app = createApp(App); app.use(VueQueryPlugin); const router = createRouter({ - history: createWebHistory(), + history: createWebHistory(import.meta.env.BASE_URL), routes: [], }); router.beforeEach((to, from, next) => { @@ -26,5 +27,6 @@ router.beforeEach((to, from, next) => { }); routes.forEach(route => router.addRoute(route)); app.use(router); +init(app); app.mount('#app'); diff --git a/frontend/apps/portal/src/pages/ApplicationPage.vue b/frontend/apps/portal/src/pages/ApplicationPage.vue index 4fd191b4a..ceb76522d 100644 --- a/frontend/apps/portal/src/pages/ApplicationPage.vue +++ b/frontend/apps/portal/src/pages/ApplicationPage.vue @@ -2,25 +2,35 @@ import { useRoute, useRouter } from 'vue-router'; import IntroSection from '@root/components/IntroSection.vue'; import { useApplications } from '@root/composables/useApplication'; -import { computed, ref, toRef } from 'vue'; +import { computed, ref, toRef, watch } from 'vue'; import { usePages } from '@root/composables/usePage'; import FullArticle from '@root/components/FullArticle.vue'; const route = useRoute(); -const applicationName = route.meta.application as string; -const heroImageUrl = route.meta.heroImageUrl as string; + +const applicationName = toRef(route.meta.application as string); +const heroImageUrl = toRef(route.meta.heroImageUrl as string); + +watch(route, (nv) => { + if (nv.meta.application) { + applicationName.value = nv.meta.application as string; + } + if (nv.meta.heroImageUrl) { + heroImageUrl.value = nv.meta.heroImageUrl as string; + } +}); // Application const { data: applications } = useApplications(); const application = computed(() => { if (applications.value) { - return applications.value.find(application => application.name === applicationName); + return applications.value.find(application => application.name === applicationName.value); } return null; }); // Pages -const { data: pages } = usePages(toRef(applicationName)); +const { data: pages } = usePages(applicationName); const sortedPages = computed(() => { return [...pages.value || []].sort((a, b) => b.priority - a.priority); }); @@ -41,7 +51,10 @@ const currentPage = computed(() => { if (articleSection.value) articleSection.value.scrollIntoView(true); return sortedPages.value.find(page => page.id === route.query.page); } - return sortedPages.value[0]; + if (sortedPages.value.length > 0) { + return sortedPages.value[0]; + } + return null; }); const router = useRouter(); diff --git a/frontend/apps/portal/src/pages/TrainingsPage.vue b/frontend/apps/portal/src/pages/TrainingsPage.vue index 04b5f8232..ba791280e 100644 --- a/frontend/apps/portal/src/pages/TrainingsPage.vue +++ b/frontend/apps/portal/src/pages/TrainingsPage.vue @@ -7,12 +7,12 @@ import { useRoute, useRouter } from 'vue-router'; import { useApplications } from '@root/composables/useApplication'; import { usePages } from '@root/composables/usePage'; import { createDate, now } from '@kwai/date'; +import { KwaiButton } from '@kwai/ui'; import { useTrainingDays, useTrainings } from '@root/composables/useTraining'; import TrainingTimeline from '@root/pages/trainings/components/TrainingTimeline.vue'; import SectionTitle from '@root/components/SectionTitle.vue'; import LeftArrowIcon from '@root/components/icons/LeftArrowIcon.vue'; import RightArrowIcon from '@root/components/icons/RightArrowIcon.vue'; -import PrimaryButton from '@root/components/PrimaryButton.vue'; import FullArticle from '@root/components/FullArticle.vue'; import CoachList from '@root/pages/trainings/components/CoachList.vue'; @@ -176,24 +176,15 @@ const showNextMonth = () => { Trainingsrooster
- + Vorige Maand - - + + Deze Maand - - + + Volgende Maand - +

{{ start.format("MMMM") }} {{ start.format("YYYY") }} diff --git a/frontend/apps/portal/src/style.css b/frontend/apps/portal/src/style.css new file mode 100644 index 000000000..688d24c35 --- /dev/null +++ b/frontend/apps/portal/src/style.css @@ -0,0 +1,75 @@ + +/* Primary and Surface Palettes */ +:root { + --p-primary-50: #fef2f2; + --p-primary-100: #fee2e2; + --p-primary-200: #fecaca; + --p-primary-300: #fca5a5; + --p-primary-400: #f87171; + --p-primary-500: #ef4444; + --p-primary-600: #dc2626; + --p-primary-700: #b91c1c; + --p-primary-800: #991b1b; + --p-primary-900: #7f1d1d; + --p-primary-950: #451a03; + --p-surface-0: #ffffff; + --p-surface-50: #fafafa; + --p-surface-100: #f4f4f5; + --p-surface-200: #e4e4e7; + --p-surface-300: #d4d4d8; + --p-surface-400: #a1a1aa; + --p-surface-500: #71717a; + --p-surface-600: #52525b; + --p-surface-700: #3f3f46; + --p-surface-800: #27272a; + --p-surface-900: #18181b; + --p-surface-950: #09090b; + --p-content-border-radius: 6px; +} + +/* Light */ +:root { + --p-primary-color: var(--p-primary-600); + --p-primary-contrast-color: var(--p-surface-0); + --p-primary-hover-color: var(--p-primary-700); + --p-primary-active-color: var(--p-primary-800); + --p-content-border-color: var(--p-surface-200); + --p-content-hover-background: var(--p-surface-100); + --p-content-hover-color: var(--p-surface-800); + --p-highlight-background: var(--p-primary-50); + --p-highlight-color: var(--p-primary-800); + --p-highlight-focus-background: var(--p-primary-200); + --p-highlight-focus-color: var(--p-primary-900); + --p-text-color: var(--p-surface-700); + --p-text-hover-color: var(--p-surface-800); + --p-text-muted-color: var(--p-surface-500); + --p-text-hover-muted-color: var(--p-surface-600); +} + +/* + * Dark Mode + * Defaults to system, change the selector to match the darkMode in tailwind.config. + * For example; + * darkMode: ['selector', '[class*="app-dark"]'] + * should be; + * :root[class="app-dark"] { +*/ +@media (prefers-color-scheme: dark) { + :root { + --p-primary-color: var(--p-primary-400); + --p-primary-contrast-color: var(--p-surface-900); + --p-primary-hover-color: var(--p-primary-300); + --p-primary-active-color: var(--p-primary-200); + --p-content-border-color: var(--p-surface-700); + --p-content-hover-background: var(--p-surface-800); + --p-content-hover-color: var(--p-surface-0); + --p-highlight-background: color-mix(in srgb, var(--p-primary-400), transparent 84%); + --p-highlight-color: rgba(255, 255, 255, 0.87); + --p-highlight-focus-background: color-mix(in srgb, var(--p-primary-400), transparent 76%); + --p-highlight-focus-color: rgba(255, 255, 255, 0.87); + --p-text-color: var(--p-surface-0); + --p-text-hover-color: var(--p-surface-0); + --p-text-muted-color: var(--p-surface-400); + --p-text-hover-muted-color: var(--p-surface-300); + } +} diff --git a/frontend/apps/portal/tailwind.config.js b/frontend/apps/portal/tailwind.config.js index f2a53ce40..a56b03390 100644 --- a/frontend/apps/portal/tailwind.config.js +++ b/frontend/apps/portal/tailwind.config.js @@ -1,12 +1,13 @@ /** @type {import('tailwindcss').Config} */ +import primeui from 'tailwindcss-primeui'; + module.exports = { content: [ - './index.html', './src/**/*.{html,js,ts,vue,jsx,tsx}', '../../packages/kwai-ui/src/**/*.{html,js,ts,vue,jsx,tsx}', ], theme: { extend: {}, }, - plugins: [], + plugins: [primeui], }; diff --git a/frontend/apps/portal/vite.config.ts b/frontend/apps/portal/vite.config.ts index 36692f45d..5e9b1942c 100644 --- a/frontend/apps/portal/vite.config.ts +++ b/frontend/apps/portal/vite.config.ts @@ -1,4 +1,4 @@ -import { defineConfig, splitVendorChunkPlugin } from 'vite'; +import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import { existsSync } from 'fs'; @@ -19,18 +19,32 @@ const resolveTheme = (path: string) => { return original; }; -export default defineConfig(() => { +export default defineConfig(({ mode }) => { return { - base: '/', + base: '/apps/portal/', server: { + origin: 'http://localhost:3000', host: '0.0.0.0', port: 3000, }, + build: { + manifest: true, + rollupOptions: { + input: 'src/index.ts', + }, + }, plugins: [ - vue(), splitVendorChunkPlugin(), visualizer(), + vue(), + visualizer(), ], resolve: { alias: [ + { + find: '@kwai/ui', + replacement: mode === 'production' + ? '@kwai/ui' + : resolve(__dirname, '../../packages/kwai-ui/src/'), + }, { find: '@theme', replacement: '', diff --git a/frontend/docs/index.md b/frontend/docs/index.md index d1d4ca39e..1b9bd98bc 100644 --- a/frontend/docs/index.md +++ b/frontend/docs/index.md @@ -3,8 +3,7 @@ The frontend consists of several single page applications. [Vue](https://vuejs.org) is used as JavaScript framework. The frontend code is written with [Typescript](https://www.typescriptlang.org/). -The code is structured as a mono repository. It contains applications -and libraries. +The code is structured as a mono repository. It contains applications and libraries. ## Install @@ -15,53 +14,28 @@ Clone the repository to your system. [npm](https://www.npmjs.com/) is used as packaging and dependency management tool. Make sure it is available. -Use npm to install all dependencies: +Make `frontend` the current directory and use npm to install all dependencies: `npm install` +[Task](https://taskfile.dev/) can be used as runner and build tool. + ### Configuration The frontend uses a config package. ## Development -A development version of the frontend can be started: +A development version of the frontend can be started. Make `frontend` the current directory +and run the `dev_apps` task. This task will build all the packages from the monorepo +and build and serve the applications. -`npm run dev` +`task dev_apps` [Vite](https://vitejs.dev/) is the local development server. -Each application will have a vite server. To serve all applications -from one url, Nginx can be used as reverse proxy. Use the following -configuration for Nginx: - -```` -server { - listen 80; - include /etc/nginx/mime.types; - - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; # allow websockets - proxy_set_header Connection "upgrade"; - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-Host $host:$server_port; - - location /apps/author { - proxy_pass http://localhost:3001/apps/author; - } - location /apps/coach { - proxy_pass http://localhost:3003/apps/coach; - } - location /apps/auth { - proxy_pass http://localhost:3002/apps/auth; - } - location / { - proxy_pass http://localhost:3000/; - } -} -```` +Each application will have a vite server. + +The FastAPI backend is used to serve all applications. ## Build @@ -69,4 +43,8 @@ To create a production version of the frontend: `npm run build` +or + +`task build_apps` + This will create dist folders in each application. diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c5c836e13..bded0bb77 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,14 +12,15 @@ "packages/*" ], "devDependencies": { + "@go-task/cli": "^3.39.0", "@vue/test-utils": "^2.4.3", "eslint-config-kwai": "*", "msw": "^2.0.11", "rollup-plugin-visualizer": "^5.11.0", "syncpack": "^12.3.2", - "turbo": "^1.13.2", "typescript": "^5.2.2", - "vite": "^4.5.3" + "vite": "^5.4.11", + "vitest": "^2.0.5" }, "engines": { "node": ">=18.0.0" @@ -32,8 +33,9 @@ "@kwai/api": "*", "@kwai/config": "*", "@kwai/ui": "*", - "@vueuse/core": "^10.9.0", + "@vueuse/core": "11.0.3", "pinia": "^2.1.7", + "tailwindcss-primeui": "^0.3.4", "vee-validate": "^4.12.6", "vue": "^3.4.25", "vue-i18n": "^9.13.1", @@ -41,12 +43,12 @@ }, "devDependencies": { "@intlify/unplugin-vue-i18n": "^1.4.0", - "@vitejs/plugin-vue": "^4.5.0", + "@vitejs/plugin-vue": "^5.2.1", "@vue/tsconfig": "^0.4.0", "autoprefixer": "^10.4.16", - "postcss": "^8.4.31", - "tailwindcss": "^3.4.3", - "vue-tsc": "^1.8.24" + "postcss": "^8.4.49", + "tailwindcss": "^3.4.15", + "vue-tsc": "^1.8.27" } }, "apps/author": { @@ -60,6 +62,7 @@ "@kwai/types": "*", "@kwai/ui": "*", "@tanstack/vue-query": "^5.32.0", + "tailwindcss-primeui": "^0.3.4", "vee-validate": "^4.12.6", "vue": "^3.4.25", "vue-i18n": "^9.13.1", @@ -67,12 +70,12 @@ "zod": "^3.23.4" }, "devDependencies": { - "@vitejs/plugin-vue": "^4.5.0", + "@vitejs/plugin-vue": "^5.2.1", "@vue/tsconfig": "^0.4.0", "autoprefixer": "^10.4.16", - "postcss": "^8.4.31", - "tailwindcss": "^3.4.3", - "vue-tsc": "^1.8.24" + "postcss": "^8.4.49", + "tailwindcss": "^3.4.15", + "vue-tsc": "^1.8.27" } }, "apps/author/node_modules/@intlify/unplugin-vue-i18n": { @@ -124,7 +127,8 @@ "@kwai/types": "*", "@kwai/ui": "*", "@tanstack/vue-query": "^5.32.0", - "@vueuse/core": "^10.9.0", + "@vueuse/core": "11.0.3", + "tailwindcss-primeui": "^0.3.4", "vee-validate": "^4.12.6", "vue": "^3.4.25", "vue-i18n": "^9.13.1", @@ -132,11 +136,12 @@ "zod": "^3.23.4" }, "devDependencies": { - "@vitejs/plugin-vue": "^4.5.0", + "@vitejs/plugin-vue": "^5.2.1", "@vue/tsconfig": "^0.4.0", "autoprefixer": "^10.4.16", - "postcss": "^8.4.31", - "tailwindcss": "^3.4.3", + "jsdom": "^25.0.0", + "postcss": "^8.4.49", + "tailwindcss": "^3.4.15", "vue-tsc": "^1.8.27" } }, @@ -189,8 +194,9 @@ "@kwai/types": "*", "@kwai/ui": "*", "@tanstack/vue-query": "^5.32.0", - "@vuepic/vue-datepicker": "8.4.0", - "@vueuse/core": "^10.9.0", + "@vuepic/vue-datepicker": "9.0.3", + "@vueuse/core": "11.0.3", + "tailwindcss-primeui": "^0.3.4", "vee-validate": "^4.12.6", "vue": "^3.4.25", "vue-i18n": "^9.13.1", @@ -198,12 +204,12 @@ "zod": "^3.23.4" }, "devDependencies": { - "@vitejs/plugin-vue": "^4.5.0", + "@vitejs/plugin-vue": "^5.2.1", "@vue/tsconfig": "^0.4.0", "autoprefixer": "^10.4.16", - "postcss": "^8.4.31", - "tailwindcss": "^3.4.3", - "vue-tsc": "^1.8.24" + "postcss": "^8.4.49", + "tailwindcss": "^3.4.15", + "vue-tsc": "^1.8.27" } }, "apps/coach/node_modules/@intlify/unplugin-vue-i18n": { @@ -254,18 +260,19 @@ "@kwai/types": "*", "@kwai/ui": "*", "@tanstack/vue-query": "^5.32.0", - "@vueuse/core": "^10.9.0", - "@vueuse/router": "^10.6.1", + "@vueuse/core": "11.0.3", + "@vueuse/router": "11.0.3", + "tailwindcss-primeui": "^0.3.4", "vue": "^3.4.25", "vue-router": "^4.3.2" }, "devDependencies": { - "@vitejs/plugin-vue": "^4.5.0", + "@vitejs/plugin-vue": "^5.2.1", "@vue/tsconfig": "^0.4.0", "autoprefixer": "^10.4.16", - "postcss": "^8.4.31", - "tailwindcss": "^3.4.3", - "vue-tsc": "^1.8.24" + "postcss": "^8.4.49", + "tailwindcss": "^3.4.15", + "vue-tsc": "^1.8.27" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -280,7 +287,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, "engines": { "node": ">=10" }, @@ -399,12 +405,12 @@ } }, "node_modules/@bundled-es-modules/cookie": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz", - "integrity": "sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.1.tgz", + "integrity": "sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==", "dev": true, "dependencies": { - "cookie": "^0.5.0" + "cookie": "^0.7.2" } }, "node_modules/@bundled-es-modules/statuses": { @@ -416,6 +422,16 @@ "statuses": "^2.0.1" } }, + "node_modules/@bundled-es-modules/tough-cookie": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@bundled-es-modules/tough-cookie/-/tough-cookie-0.1.6.tgz", + "integrity": "sha512-dvMHbL464C0zI+Yqxbz6kZ5TOEp7GLW+pry/RWndAR8MJQAXZ2rPmIs8tziTZjeIyhSNZgZbCePtfSbdWqStJw==", + "dev": true, + "dependencies": { + "@types/tough-cookie": "^4.0.5", + "tough-cookie": "^4.1.4" + } + }, "node_modules/@effect/schema": { "version": "0.66.5", "resolved": "https://registry.npmjs.org/@effect/schema/-/schema-0.66.5.tgz", @@ -426,10 +442,26 @@ "fast-check": "^3.13.2" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -443,9 +475,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -459,9 +491,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -475,9 +507,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -491,9 +523,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -507,9 +539,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -523,9 +555,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -539,9 +571,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -555,9 +587,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -571,9 +603,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -587,9 +619,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -603,9 +635,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -619,9 +651,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -635,9 +667,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -651,9 +683,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -667,9 +699,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -683,9 +715,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -699,9 +731,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -715,9 +747,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -731,9 +763,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -747,9 +779,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -763,9 +795,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -873,6 +905,25 @@ "node": ">= 8.0.0" } }, + "node_modules/@go-task/cli": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/@go-task/cli/-/cli-3.39.0.tgz", + "integrity": "sha512-KhJ3Ao0ZR9JmmA5ad8ovFwr2mJmSLVqd0Y7hJBI130MZ9JXPmxavkoDc10d4oul/TCKG6nGwypru/OmFqkHTTw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@go-task/go-npm": "^0.2.0" + } + }, + "node_modules/@go-task/go-npm": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@go-task/go-npm/-/go-npm-0.2.0.tgz", + "integrity": "sha512-vQbdtBvesHm8EUFHX8QKg4rbBodmu9VsAXH1ozpbiN5jdTMOYHTCMM31EurAYmY+rNNtxJQ4JGy6t383RPlqbw==", + "dev": true, + "bin": { + "go-npm": "bin/index.js" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -930,37 +981,36 @@ "dev": true }, "node_modules/@inquirer/confirm": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.5.tgz", - "integrity": "sha512-6+dwZrpko5vr5EFEQmUbfBVhtu6IsnB8lQNsLHgO9S9fbfS5J6MuUj+NY0h98pPpYZXEazLR7qzypEDqVzf6aQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.0.2.tgz", + "integrity": "sha512-KJLUHOaKnNCYzwVbryj3TNBxyZIrr56fR5N45v6K9IPrbT6B7DcudBMfylkV1A8PUdJE15mybkEQyp2/ZUpxUA==", "dev": true, "dependencies": { - "@inquirer/core": "^8.0.1", - "@inquirer/type": "^1.3.0" + "@inquirer/core": "^10.1.0", + "@inquirer/type": "^3.0.1" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" } }, "node_modules/@inquirer/core": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-8.0.1.tgz", - "integrity": "sha512-qJRk1y51Os2ARc11Bg2N6uIwiQ9qBSrmZeuMonaQ/ntFpb4+VlcQ8Gl1TFH67mJLz3HA2nvuave0nbv6Lu8pbg==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.0.tgz", + "integrity": "sha512-I+ETk2AL+yAVbvuKx5AJpQmoaWhpiTFOg/UJb7ZkMAK4blmtG8ATh5ct+T/8xNld0CZG/2UhtkdMwpgvld92XQ==", "dev": true, "dependencies": { - "@inquirer/figures": "^1.0.1", - "@inquirer/type": "^1.3.0", - "@types/mute-stream": "^0.0.4", - "@types/node": "^20.12.7", - "@types/wrap-ansi": "^3.0.0", + "@inquirer/figures": "^1.0.8", + "@inquirer/type": "^3.0.1", "ansi-escapes": "^4.3.2", - "chalk": "^4.1.2", - "cli-spinners": "^2.9.2", "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", + "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" @@ -1022,21 +1072,24 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.1.tgz", - "integrity": "sha512-mtup3wVKia3ZwULPHcbs4Mor8Voi+iIXEWD7wCNbIO6lYR62oPCTQyrddi5OMYVXHzeCSoneZwJuS8sBvlEwDw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.8.tgz", + "integrity": "sha512-tKd+jsmhq21AP1LhexC0pPwsCxEhGgAkg28byjJAd+xhmIs8LUX8JbUc3vBf3PhLxWiB5EvyBE5X7JSPAqMAqg==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/@inquirer/type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.3.0.tgz", - "integrity": "sha512-RW4Zf6RCTnInRaOZuRHTqAUl+v6VJuQGglir7nW2BkT3OXOphMhkIFhvFRjorBx2l0VwtC/M4No8vYR65TdN9Q==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.1.tgz", + "integrity": "sha512-+ksJMIy92sOAiAccGpcKZUc3bYO07cADnscIxHBknEm3uNts3movSmBofc1908BNy5edKscxYeAdaX1NXkHS6A==", "dev": true, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" } }, "node_modules/@intlify/bundle-utils": { @@ -1179,7 +1232,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -1192,23 +1244,10 @@ "node": ">=12" } }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1222,7 +1261,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1231,21 +1269,19 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1428,26 +1464,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@mswjs/cookies": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-1.1.0.tgz", - "integrity": "sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw==", - "dev": true, - "engines": { - "node": ">=18" - } - }, "node_modules/@mswjs/interceptors": { - "version": "0.26.15", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.26.15.tgz", - "integrity": "sha512-HM47Lu1YFmnYHKMBynFfjCp0U/yRskHj/8QEJW0CBEPOlw8Gkmjfll+S9b8M7V5CNDw2/ciRxjjnWeaCiblSIQ==", + "version": "0.37.1", + "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.37.1.tgz", + "integrity": "sha512-SvE+tSpcX884RJrPCskXxoS965Ky/pYABDEhWW6oeSRhpUDLrS5nTvT5n1LLSDVDYvty4imVmXsy+3/ROVuknA==", "dev": true, "dependencies": { "@open-draft/deferred-promise": "^2.2.0", "@open-draft/logger": "^0.3.0", "@open-draft/until": "^2.0.0", "is-node-process": "^1.2.0", - "outvariant": "^1.2.1", + "outvariant": "^1.4.3", "strict-event-emitter": "^0.5.1" }, "engines": { @@ -1518,7 +1545,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "optional": true, "engines": { "node": ">=14" @@ -1535,6 +1561,52 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@primeuix/styled": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.3.2.tgz", + "integrity": "sha512-ColZes0+/WKqH4ob2x8DyNYf1NENpe5ZguOvx5yCLxaP8EIMVhLjWLO/3umJiDnQU4XXMLkn2mMHHw+fhTX/mw==", + "dependencies": { + "@primeuix/utils": "^0.3.2" + }, + "engines": { + "node": ">=12.11.0" + } + }, + "node_modules/@primeuix/utils": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@primeuix/utils/-/utils-0.3.2.tgz", + "integrity": "sha512-B+nphqTQeq+i6JuICLdVWnDMjONome2sNz0xI65qIOyeB4EF12CoKRiCsxuZ5uKAkHi/0d1LqlQ9mIWRSdkavw==", + "engines": { + "node": ">=12.11.0" + } + }, + "node_modules/@primevue/core": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@primevue/core/-/core-4.2.4.tgz", + "integrity": "sha512-QFvPcGSvyIhZPLdnjJnYrwbDtwbA1/FyGLI7VYDgYv4twsgtLw0kgKDyWB1uwM0xdJhv8CCmu7hfxcsPaLuIFg==", + "dependencies": { + "@primeuix/styled": "^0.3.2", + "@primeuix/utils": "^0.3.2" + }, + "engines": { + "node": ">=12.11.0" + }, + "peerDependencies": { + "vue": "^3.3.0" + } + }, + "node_modules/@primevue/icons": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@primevue/icons/-/icons-4.2.4.tgz", + "integrity": "sha512-vteUFM7qvWiDJWxhBbDRgc2VY6kQQyJ91yOukqfWHy4gAgfTz1jiUXMAzc7j269oh4CNFpTNhCe9riS7402HGg==", + "dependencies": { + "@primeuix/utils": "^0.3.2", + "@primevue/core": "4.2.4" + }, + "engines": { + "node": ">=12.11.0" + } + }, "node_modules/@rollup/pluginutils": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", @@ -1556,6 +1628,240 @@ } } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", + "integrity": "sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.27.4.tgz", + "integrity": "sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz", + "integrity": "sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.27.4.tgz", + "integrity": "sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.27.4.tgz", + "integrity": "sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.27.4.tgz", + "integrity": "sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.27.4.tgz", + "integrity": "sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.27.4.tgz", + "integrity": "sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.27.4.tgz", + "integrity": "sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.27.4.tgz", + "integrity": "sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.27.4.tgz", + "integrity": "sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.27.4.tgz", + "integrity": "sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.27.4.tgz", + "integrity": "sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz", + "integrity": "sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz", + "integrity": "sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.27.4.tgz", + "integrity": "sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.27.4.tgz", + "integrity": "sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.27.4.tgz", + "integrity": "sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rushstack/node-core-library": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-4.0.2.tgz", @@ -1669,12 +1975,6 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, "node_modules/@sindresorhus/merge-streams": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", @@ -1688,15 +1988,15 @@ } }, "node_modules/@tailwindcss/forms": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.7.tgz", - "integrity": "sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==", + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.9.tgz", + "integrity": "sha512-tM4XVr2+UVTxXJzey9Twx48c1gcxFStqn1pQz0tRsX8o3DvxhN5oY5pvyAbUx7VTaZxpej4Zzvc6h+1RJBzpIg==", "dev": true, "dependencies": { "mini-svg-data-uri": "^1.2.3" }, "peerDependencies": { - "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1" + "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20" } }, "node_modules/@tanstack/match-sorter-utils": { @@ -1778,21 +2078,6 @@ "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", "dev": true }, - "node_modules/@types/chai": { - "version": "4.3.14", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.14.tgz", - "integrity": "sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==", - "dev": true - }, - "node_modules/@types/chai-subset": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.5.tgz", - "integrity": "sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==", - "dev": true, - "dependencies": { - "@types/chai": "*" - } - }, "node_modules/@types/cookie": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", @@ -1800,9 +2085,9 @@ "dev": true }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" }, "node_modules/@types/json-schema": { "version": "7.0.15", @@ -1815,20 +2100,12 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "peer": true }, - "node_modules/@types/mute-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz", - "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/node": { "version": "20.12.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "dev": true, + "peer": true, "dependencies": { "undici-types": "~5.26.4" } @@ -1844,17 +2121,17 @@ "integrity": "sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==", "dev": true }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true + }, "node_modules/@types/web-bluetooth": { "version": "0.0.20", "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==" }, - "node_modules/@types/wrap-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", - "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==", - "dev": true - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", @@ -2084,108 +2361,128 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "node_modules/@vitejs/plugin-vue": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.6.2.tgz", - "integrity": "sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz", + "integrity": "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==", "dev": true, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^18.0.0 || >=20.0.0" }, "peerDependencies": { - "vite": "^4.0.0 || ^5.0.0", + "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "node_modules/@vitest/expect": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz", - "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.6.tgz", + "integrity": "sha512-9M1UR9CAmrhJOMoSwVnPh2rELPKhYo0m/CSgqw9PyStpxtkwhmdM6XYlXGKeYyERY1N6EIuzkQ7e3Lm1WKCoUg==", "dev": true, "dependencies": { - "@vitest/spy": "0.34.6", - "@vitest/utils": "0.34.6", - "chai": "^4.3.10" + "@vitest/spy": "2.1.6", + "@vitest/utils": "2.1.6", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/runner": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz", - "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==", + "node_modules/@vitest/mocker": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.6.tgz", + "integrity": "sha512-MHZp2Z+Q/A3am5oD4WSH04f9B0T7UvwEb+v5W0kCYMhtXGYbdyl2NUk1wdSMqGthmhpiThPDp/hEoVwu16+u1A==", "dev": true, "dependencies": { - "@vitest/utils": "0.34.6", - "p-limit": "^4.0.0", - "pathe": "^1.1.1" + "@vitest/spy": "2.1.6", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" }, "funding": { "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "node_modules/@vitest/runner/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "@types/estree": "^1.0.0" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.6.tgz", + "integrity": "sha512-exZyLcEnHgDMKc54TtHca4McV4sKT+NKAe9ix/yhd/qkYb/TP8HTyXRFDijV19qKqTZM0hPL4753zU/U8L/gAA==", + "dev": true, + "dependencies": { + "tinyrainbow": "^1.2.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/runner/node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "node_modules/@vitest/runner": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.6.tgz", + "integrity": "sha512-SjkRGSFyrA82m5nz7To4CkRSEVWn/rwQISHoia/DB8c6IHIhaE/UNAo+7UfeaeJRE979XceGl00LNkIz09RFsA==", "dev": true, - "engines": { - "node": ">=12.20" + "dependencies": { + "@vitest/utils": "2.1.6", + "pathe": "^1.1.2" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz", - "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.6.tgz", + "integrity": "sha512-5JTWHw8iS9l3v4/VSuthCndw1lN/hpPB+mlgn1BUhFbobeIUj1J1V/Bj2t2ovGEmkXLTckFjQddsxS5T6LuVWw==", "dev": true, "dependencies": { - "magic-string": "^0.30.1", - "pathe": "^1.1.1", - "pretty-format": "^29.5.0" + "@vitest/pretty-format": "2.1.6", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/spy": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", - "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.6.tgz", + "integrity": "sha512-oTFObV8bd4SDdRka5O+mSh5w9irgx5IetrD5i+OsUUsk/shsBoHifwCzy45SAORzAhtNiprUVaK3hSCCzZh1jQ==", "dev": true, "dependencies": { - "tinyspy": "^2.1.1" + "tinyspy": "^3.0.2" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz", - "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.6.tgz", + "integrity": "sha512-ixNkFy3k4vokOUTU2blIUvOgKq/N2PW8vKIjZZYsGJCMX69MRa9J2sKqX5hY/k5O5Gty3YJChepkqZ3KM9LyIQ==", "dev": true, "dependencies": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^29.5.0" + "@vitest/pretty-format": "2.1.6", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" }, "funding": { "url": "https://opencollective.com/vitest" @@ -2394,9 +2691,9 @@ "dev": true }, "node_modules/@vuepic/vue-datepicker": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-8.4.0.tgz", - "integrity": "sha512-Twgvqwd5GrQf3JT2DvAQ/Ku0+sM51zsH1OkQKoRwYqJyF+EugItS8I0CveYmcI3Gbu92RZ9C3DMutvkaiuDzAQ==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@vuepic/vue-datepicker/-/vue-datepicker-9.0.3.tgz", + "integrity": "sha512-OtCAKG+CkVBpCwnPx7/BGRF+/z+jDzNl2cMBpcr8j2NkAN+13xkUt7sctbOVKbG/jhuXtKoUSedI69e0cDXPXw==", "dependencies": { "date-fns": "^3.6.0" }, @@ -2408,23 +2705,23 @@ } }, "node_modules/@vueuse/core": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.9.0.tgz", - "integrity": "sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-11.0.3.tgz", + "integrity": "sha512-RENlh64+SYA9XMExmmH1a3TPqeIuJBNNB/63GT35MZI+zpru3oMRUA6cEFr9HmGqEgUisurwGwnIieF6qu3aXw==", "dependencies": { "@types/web-bluetooth": "^0.0.20", - "@vueuse/metadata": "10.9.0", - "@vueuse/shared": "10.9.0", - "vue-demi": ">=0.14.7" + "@vueuse/metadata": "11.0.3", + "@vueuse/shared": "11.0.3", + "vue-demi": ">=0.14.10" }, "funding": { "url": "https://github.com/sponsors/antfu" } }, "node_modules/@vueuse/core/node_modules/vue-demi": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", - "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", "hasInstallScript": true, "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", @@ -2447,20 +2744,20 @@ } }, "node_modules/@vueuse/metadata": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.9.0.tgz", - "integrity": "sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-11.0.3.tgz", + "integrity": "sha512-+FtbO4SD5WpsOcQTcC0hAhNlOid6QNLzqedtquTtQ+CRNBoAt9GuV07c6KNHK1wCmlq8DFPwgiLF2rXwgSHX5Q==", "funding": { "url": "https://github.com/sponsors/antfu" } }, "node_modules/@vueuse/router": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/@vueuse/router/-/router-10.9.0.tgz", - "integrity": "sha512-MOmrCMQlRuPS4PExE1hy8T0XbZUXaNbEuh7CAG5mC8kdvdgANQMkdvJ7vIEOP27n5mXK/4YjvXJOZSsur4E0QQ==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@vueuse/router/-/router-11.0.3.tgz", + "integrity": "sha512-Sa8wNATd4DoAWkO5NgV+sfTU9dOtC8pi+GEbtzOdC7/99fWK8k5/dfbfkt+OWcpwXoToNidBqnAZafknlYb2ig==", "dependencies": { - "@vueuse/shared": "10.9.0", - "vue-demi": ">=0.14.7" + "@vueuse/shared": "11.0.3", + "vue-demi": ">=0.14.10" }, "funding": { "url": "https://github.com/sponsors/antfu" @@ -2470,9 +2767,9 @@ } }, "node_modules/@vueuse/router/node_modules/vue-demi": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", - "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", "hasInstallScript": true, "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", @@ -2495,20 +2792,20 @@ } }, "node_modules/@vueuse/shared": { - "version": "10.9.0", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.9.0.tgz", - "integrity": "sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-11.0.3.tgz", + "integrity": "sha512-0rY2m6HS5t27n/Vp5cTDsKTlNnimCqsbh/fmT2LgE+aaU42EMfXo8+bNX91W9I7DDmxfuACXMmrd7d79JxkqWA==", "dependencies": { - "vue-demi": ">=0.14.7" + "vue-demi": ">=0.14.10" }, "funding": { "url": "https://github.com/sponsors/antfu" } }, "node_modules/@vueuse/shared/node_modules/vue-demi": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", - "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", "hasInstallScript": true, "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", @@ -2558,13 +2855,16 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, "engines": { - "node": ">=0.4.0" + "node": ">= 14" } }, "node_modules/ajv": { @@ -2622,7 +2922,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -2647,8 +2946,7 @@ "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" }, "node_modules/anymatch": { "version": "3.1.3", @@ -2665,8 +2963,7 @@ "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" }, "node_modules/argparse": { "version": "2.0.1", @@ -2796,14 +3093,20 @@ } }, "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "engines": { - "node": "*" + "node": ">=12" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, "node_modules/autoprefixer": { "version": "10.4.19", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", @@ -2886,11 +3189,11 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -2988,15 +3291,14 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, "engines": { "node": ">= 6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001612", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", - "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", + "version": "1.0.30001684", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz", + "integrity": "sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==", "dev": true, "funding": [ { @@ -3014,21 +3316,19 @@ ] }, "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", + "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", "dev": true, "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=12" } }, "node_modules/chalk": { @@ -3074,15 +3374,12 @@ } }, "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, "engines": { - "node": "*" + "node": ">= 16" } }, "node_modules/chokidar": { @@ -3232,6 +3529,18 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", @@ -3268,9 +3577,9 @@ } }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "engines": { "node": ">= 0.6" @@ -3303,9 +3612,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3326,11 +3635,36 @@ "node": ">=4" } }, + "node_modules/cssstyle": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", + "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", + "dev": true, + "dependencies": { + "rrweb-cssom": "^0.7.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -3403,11 +3737,11 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3418,14 +3752,17 @@ } } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, "engines": { "node": ">=6" } @@ -3478,21 +3815,20 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=0.4.0" } }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -3515,8 +3851,7 @@ "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, "node_modules/doctrine": { "version": "3.0.0", @@ -3532,8 +3867,7 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/editorconfig": { "version": "1.0.4", @@ -3568,8 +3902,7 @@ "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/enquirer": { "version": "2.4.1", @@ -3715,6 +4048,12 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, "node_modules/es-object-atoms": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", @@ -3768,9 +4107,9 @@ } }, "node_modules/esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "bin": { @@ -3780,28 +4119,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escalade": { @@ -4382,6 +4722,15 @@ "node": ">=0.10.0" } }, + "node_modules/expect-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz", + "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-check": { "version": "3.17.2", "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.17.2.tgz", @@ -4459,9 +4808,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4515,7 +4864,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -4527,6 +4875,20 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -4628,15 +4990,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -4689,7 +5042,6 @@ "version": "10.3.12", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", - "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.6", @@ -4916,6 +5268,56 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -5146,7 +5548,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -5223,6 +5624,12 @@ "node": ">=8" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -5350,7 +5757,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -5365,10 +5771,9 @@ } }, "node_modules/jiti": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", - "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", - "dev": true, + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", "bin": { "jiti": "bin/jiti.js" } @@ -5426,6 +5831,55 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdom": { + "version": "25.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.0.tgz", + "integrity": "sha512-OhoFVT59T7aEq75TVw9xxEfkXgacpqAhQaYgP9y/fDqWQCMB/b1H66RfmPm/MaeaAIU9nDwMOVTlPN51+ao6CQ==", + "dev": true, + "dependencies": { + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.4", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -5523,7 +5977,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, "engines": { "node": ">=10" } @@ -5531,20 +5984,7 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/local-pkg": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", - "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/locate-path": { "version": "6.0.0", @@ -5623,29 +6063,25 @@ } }, "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", + "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", + "dev": true }, "node_modules/lru-cache": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "dev": true, "engines": { "node": "14 || >=16.14" } }, "node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "version": "0.30.14", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.14.tgz", + "integrity": "sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/merge2": { @@ -5657,17 +6093,38 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -5690,7 +6147,6 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -5714,7 +6170,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -5731,22 +6186,23 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/msw": { - "version": "2.2.14", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.2.14.tgz", - "integrity": "sha512-64i8rNCa1xzDK8ZYsTrVMli05D687jty8+Th+PU5VTbJ2/4P7fkQFVyDQ6ZFT5FrNR8z2BHhbY47fKNvfHrumA==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/msw/-/msw-2.6.6.tgz", + "integrity": "sha512-npfIIVRHKQX3Lw4aLWX4wBh+lQwpqdZNyJYB5K/+ktK8NhtkdsTxGK7WDrgknozcVyRI7TOqY6yBS9j2FTR+YQ==", "dev": true, "hasInstallScript": true, "dependencies": { - "@bundled-es-modules/cookie": "^2.0.0", + "@bundled-es-modules/cookie": "^2.0.1", "@bundled-es-modules/statuses": "^1.0.1", - "@inquirer/confirm": "^3.0.0", - "@mswjs/cookies": "^1.1.0", - "@mswjs/interceptors": "^0.26.14", + "@bundled-es-modules/tough-cookie": "^0.1.6", + "@inquirer/confirm": "^5.0.0", + "@mswjs/interceptors": "^0.37.0", + "@open-draft/deferred-promise": "^2.2.0", "@open-draft/until": "^2.1.0", "@types/cookie": "^0.6.0", "@types/statuses": "^2.0.4", @@ -5754,10 +6210,10 @@ "graphql": "^16.8.1", "headers-polyfill": "^4.0.2", "is-node-process": "^1.2.0", - "outvariant": "^1.4.2", - "path-to-regexp": "^6.2.0", + "outvariant": "^1.4.3", + "path-to-regexp": "^6.3.0", "strict-event-emitter": "^0.5.1", - "type-fest": "^4.9.0", + "type-fest": "^4.26.1", "yargs": "^17.7.2" }, "bin": { @@ -5770,7 +6226,7 @@ "url": "https://github.com/sponsors/mswjs" }, "peerDependencies": { - "typescript": ">= 4.7.x" + "typescript": ">= 4.8.x" }, "peerDependenciesMeta": { "typescript": { @@ -5785,19 +6241,18 @@ "dev": true }, "node_modules/mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", "dev": true, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", @@ -5890,11 +6345,16 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/nwsapi": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", + "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==", + "dev": true + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -5903,7 +6363,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, "engines": { "node": ">= 6" } @@ -6108,9 +6567,9 @@ } }, "node_modules/outvariant": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.2.tgz", - "integrity": "sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.3.tgz", + "integrity": "sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==", "dev": true }, "node_modules/p-limit": { @@ -6170,6 +6629,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -6209,7 +6680,6 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", - "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -6222,9 +6692,9 @@ } }, "node_modules/path-to-regexp": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", - "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "dev": true }, "node_modules/path-type": { @@ -6245,18 +6715,18 @@ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==" }, "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, "engines": { - "node": "*" + "node": ">= 14.16" } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -6273,7 +6743,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -6332,7 +6801,6 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, "engines": { "node": ">= 6" } @@ -6357,9 +6825,9 @@ } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "funding": [ { "type": "opencollective", @@ -6376,8 +6844,8 @@ ], "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -6387,7 +6855,6 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -6404,7 +6871,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dev": true, "dependencies": { "camelcase-css": "^2.0.1" }, @@ -6423,7 +6889,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -6458,7 +6923,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", - "dev": true, "engines": { "node": ">=14" }, @@ -6467,28 +6931,33 @@ } }, "node_modules/postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", - "dev": true, + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "postcss-selector-parser": "^6.0.11" + "postcss-selector-parser": "^6.1.1" }, "engines": { "node": ">=12.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": "^8.2.14" } }, "node_modules/postcss-selector-parser": { - "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -6500,8 +6969,7 @@ "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/prelude-ls": { "version": "1.2.1", @@ -6537,38 +7005,18 @@ "node": ">=6.0.0" } }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, + "node_modules/primevue": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/primevue/-/primevue-4.2.4.tgz", + "integrity": "sha512-aMQymoO489isReSF/bScypswOnLBU29qkeTulGj3Wntb9plvzTIWjA4+iyDOsyxGmV5GVIvD+DuTw5FNCDWgSw==", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@primeuix/styled": "^0.3.2", + "@primeuix/utils": "^0.3.2", + "@primevue/core": "4.2.4", + "@primevue/icons": "4.2.4" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/primevue": { - "version": "3.51.0", - "resolved": "https://registry.npmjs.org/primevue/-/primevue-3.51.0.tgz", - "integrity": "sha512-BdMveidLSr0fNJ5+mxuke8mMCHyiXwvfDP4iwPr6R98rl3E0Wcm1u4/RKVrL7o0Iq606SXyhPQL3LGyAfXngcA==", - "peerDependencies": { - "vue": "^3.0.0" + "node": ">=12.11.0" } }, "node_modules/proc-log": { @@ -6599,6 +7047,12 @@ "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", "dev": true }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -6623,6 +7077,12 @@ } ] }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -6642,17 +7102,10 @@ } ] }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, "dependencies": { "pify": "^2.3.0" } @@ -6713,6 +7166,12 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -6831,18 +7290,39 @@ } }, "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "version": "4.27.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.27.4.tgz", + "integrity": "sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==", "devOptional": true, + "dependencies": { + "@types/estree": "1.0.6" + }, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=14.18.0", + "node": ">=18.0.0", "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.27.4", + "@rollup/rollup-android-arm64": "4.27.4", + "@rollup/rollup-darwin-arm64": "4.27.4", + "@rollup/rollup-darwin-x64": "4.27.4", + "@rollup/rollup-freebsd-arm64": "4.27.4", + "@rollup/rollup-freebsd-x64": "4.27.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.27.4", + "@rollup/rollup-linux-arm-musleabihf": "4.27.4", + "@rollup/rollup-linux-arm64-gnu": "4.27.4", + "@rollup/rollup-linux-arm64-musl": "4.27.4", + "@rollup/rollup-linux-powerpc64le-gnu": "4.27.4", + "@rollup/rollup-linux-riscv64-gnu": "4.27.4", + "@rollup/rollup-linux-s390x-gnu": "4.27.4", + "@rollup/rollup-linux-x64-gnu": "4.27.4", + "@rollup/rollup-linux-x64-musl": "4.27.4", + "@rollup/rollup-win32-arm64-msvc": "4.27.4", + "@rollup/rollup-win32-ia32-msvc": "4.27.4", + "@rollup/rollup-win32-x64-msvc": "4.27.4", "fsevents": "~2.3.2" } }, @@ -6872,6 +7352,12 @@ } } }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==", + "dev": true + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6929,6 +7415,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/semver": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", @@ -7033,7 +7537,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "engines": { "node": ">=14" }, @@ -7069,9 +7572,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "engines": { "node": ">=0.10.0" } @@ -7098,9 +7601,9 @@ } }, "node_modules/std-env": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", - "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", + "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", "dev": true }, "node_modules/stdin-discarder": { @@ -7134,7 +7637,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -7152,7 +7654,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -7166,7 +7667,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -7174,14 +7674,12 @@ "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -7242,7 +7740,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -7258,7 +7755,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -7270,7 +7766,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -7295,23 +7790,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-literal": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz", - "integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==", - "dev": true, - "dependencies": { - "acorn": "^8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, "node_modules/sucrase": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -7333,7 +7815,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, "engines": { "node": ">= 6" } @@ -7360,6 +7841,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, "node_modules/synckit": { "version": "0.8.8", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", @@ -7452,33 +7939,32 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz", - "integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==", - "dev": true, + "version": "3.4.15", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.15.tgz", + "integrity": "sha512-r4MeXnfBmSOuKUWmXe6h2CcyfzJCEk4F0pptO5jlnYSIViUkVmsawj80N5h2lO3gwcmSb4n3PuN+e+GC1Guylw==", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", - "chokidar": "^3.5.3", + "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "fast-glob": "^3.3.0", + "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", - "jiti": "^1.21.0", + "jiti": "^1.21.6", "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", + "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", @@ -7488,11 +7974,18 @@ "node": ">=14.0.0" } }, + "node_modules/tailwindcss-primeui": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/tailwindcss-primeui/-/tailwindcss-primeui-0.3.4.tgz", + "integrity": "sha512-5+Qfoe5Kpq2Iwrd6umBUb3rQH6b7+pL4jxJUId0Su5agUM6TwCyH5Pyl9R0y3QQB3IRuTxBNmeS11B41f+30zw==", + "peerDependencies": { + "tailwindcss": ">=3.1.0" + } + }, "node_modules/tailwindcss/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -7509,7 +8002,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, "dependencies": { "any-promise": "^1.0.0" } @@ -7518,7 +8010,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -7536,24 +8027,39 @@ } }, "node_modules/tinybench": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz", - "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true + }, + "node_modules/tinyexec": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.1.tgz", + "integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==", "dev": true }, "node_modules/tinypool": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz", - "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.1.tgz", + "integrity": "sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==", + "dev": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", "dev": true, "engines": { "node": ">=14.0.0" } }, "node_modules/tinyspy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", - "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", "dev": true, "engines": { "node": ">=14.0.0" @@ -7570,6 +8076,42 @@ "node": ">=8.0" } }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", @@ -7584,8 +8126,7 @@ "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "node_modules/ts-toolbelt": { "version": "9.6.0", @@ -7631,101 +8172,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, - "node_modules/turbo": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/turbo/-/turbo-1.13.2.tgz", - "integrity": "sha512-rX/d9f4MgRT3yK6cERPAkfavIxbpBZowDQpgvkYwGMGDQ0Nvw1nc0NVjruE76GrzXQqoxR1UpnmEP54vBARFHQ==", - "dev": true, - "bin": { - "turbo": "bin/turbo" - }, - "optionalDependencies": { - "turbo-darwin-64": "1.13.2", - "turbo-darwin-arm64": "1.13.2", - "turbo-linux-64": "1.13.2", - "turbo-linux-arm64": "1.13.2", - "turbo-windows-64": "1.13.2", - "turbo-windows-arm64": "1.13.2" - } - }, - "node_modules/turbo-darwin-64": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-1.13.2.tgz", - "integrity": "sha512-CCSuD8CfmtncpohCuIgq7eAzUas0IwSbHfI8/Q3vKObTdXyN8vAo01gwqXjDGpzG9bTEVedD0GmLbD23dR0MLA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/turbo-darwin-arm64": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-1.13.2.tgz", - "integrity": "sha512-0HySm06/D2N91rJJ89FbiI/AodmY8B3WDSFTVEpu2+8spUw7hOJ8okWOT0e5iGlyayUP9gr31eOeL3VFZkpfCw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/turbo-linux-64": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-1.13.2.tgz", - "integrity": "sha512-7HnibgbqZrjn4lcfIouzlPu8ZHSBtURG4c7Bedu7WJUDeZo+RE1crlrQm8wuwO54S0siYqUqo7GNHxu4IXbioQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/turbo-linux-arm64": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-1.13.2.tgz", - "integrity": "sha512-sUq4dbpk6SNKg/Hkwn256Vj2AEYSQdG96repio894h5/LEfauIK2QYiC/xxAeW3WBMc6BngmvNyURIg7ltrePg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/turbo-windows-64": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-1.13.2.tgz", - "integrity": "sha512-DqzhcrciWq3dpzllJR2VVIyOhSlXYCo4mNEWl98DJ3FZ08PEzcI3ceudlH6F0t/nIcfSItK1bDP39cs7YoZHEA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/turbo-windows-arm64": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-1.13.2.tgz", - "integrity": "sha512-WnPMrwfCXxK69CdDfS1/j2DlzcKxSmycgDAqV0XCYpK/812KB0KlvsVAt5PjEbZGXkY88pCJ1BLZHAjF5FcbqA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -7737,19 +8183,10 @@ "node": ">= 0.8.0" } }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/type-fest": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.17.0.tgz", - "integrity": "sha512-9flrz1zkfLRH3jO3bLflmTxryzKMxVa7841VeMgBaNQGY6vH4RCcpN/sQLB7mQQYh1GZ5utT2deypMuCy4yicw==", + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.29.0.tgz", + "integrity": "sha512-RPYt6dKyemXJe7I6oNstcH24myUGSReicxcHTvCLgzm4e0n8y05dGvcGB15/SoPRBmhlMthWQ9pvKyL81ko8nQ==", "engines": { "node": ">=16" }, @@ -7866,7 +8303,8 @@ "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "dev": true, + "peer": true }, "node_modules/unicorn-magic": { "version": "0.1.0", @@ -7941,6 +8379,16 @@ "punycode": "^2.1.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -7980,32 +8428,33 @@ } }, "node_modules/vite": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz", - "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==", + "version": "5.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", + "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", "dev": true, "dependencies": { - "esbuild": "^0.18.10", - "postcss": "^8.4.27", - "rollup": "^3.27.1" + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "fsevents": "~2.3.2" + "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": ">= 14", + "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", + "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" @@ -8023,6 +8472,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, @@ -8035,32 +8487,31 @@ } }, "node_modules/vite-node": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz", - "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.6.tgz", + "integrity": "sha512-DBfJY0n9JUwnyLxPSSUmEePT21j8JZp/sR9n+/gBwQU6DcQOioPdb8/pibWfXForbirSagZCilseYIwaL3f95A==", "dev": true, "dependencies": { "cac": "^6.7.14", - "debug": "^4.3.4", - "mlly": "^1.4.0", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0" + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0 || ^6.0.0" }, "bin": { "vite-node": "vite-node.mjs" }, "engines": { - "node": ">=v14.18.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/vite-plugin-dts": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-3.9.0.tgz", - "integrity": "sha512-pwFIEYQ3LZvMafkEGvNnileb6af5JuyZsBfYQrTDYxdeGEy0OS4B4hCsLPo5YGnhK5k9EzyO6BXVO6y+Lt5T2A==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-3.9.1.tgz", + "integrity": "sha512-rVp2KM9Ue22NGWB8dNtWEr+KekN3rIgz1tWD050QnRGlriUCmaDwa7qA5zDEjbXg5lAXhYMSBJtx3q3hQIJZSg==", "dev": true, "dependencies": { "@microsoft/api-extractor": "7.43.0", @@ -8085,59 +8536,56 @@ } }, "node_modules/vitest": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz", - "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==", - "dev": true, - "dependencies": { - "@types/chai": "^4.3.5", - "@types/chai-subset": "^1.3.3", - "@types/node": "*", - "@vitest/expect": "0.34.6", - "@vitest/runner": "0.34.6", - "@vitest/snapshot": "0.34.6", - "@vitest/spy": "0.34.6", - "@vitest/utils": "0.34.6", - "acorn": "^8.9.0", - "acorn-walk": "^8.2.0", - "cac": "^6.7.14", - "chai": "^4.3.10", - "debug": "^4.3.4", - "local-pkg": "^0.4.3", - "magic-string": "^0.30.1", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.3.3", - "strip-literal": "^1.0.1", - "tinybench": "^2.5.0", - "tinypool": "^0.7.0", - "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0", - "vite-node": "0.34.6", - "why-is-node-running": "^2.2.2" + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.6.tgz", + "integrity": "sha512-isUCkvPL30J4c5O5hgONeFRsDmlw6kzFEdLQHLezmDdKQHy8Ke/B/dgdTMEgU0vm+iZ0TjW8GuK83DiahBoKWQ==", + "dev": true, + "dependencies": { + "@vitest/expect": "2.1.6", + "@vitest/mocker": "2.1.6", + "@vitest/pretty-format": "^2.1.6", + "@vitest/runner": "2.1.6", + "@vitest/snapshot": "2.1.6", + "@vitest/spy": "2.1.6", + "@vitest/utils": "2.1.6", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0 || ^6.0.0", + "vite-node": "2.1.6", + "why-is-node-running": "^2.3.0" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": ">=v14.18.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { "@edge-runtime/vm": "*", - "@vitest/browser": "*", - "@vitest/ui": "*", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "2.1.6", + "@vitest/ui": "2.1.6", "happy-dom": "*", - "jsdom": "*", - "playwright": "*", - "safaridriver": "*", - "webdriverio": "*" + "jsdom": "*" }, "peerDependenciesMeta": { "@edge-runtime/vm": { "optional": true }, + "@types/node": { + "optional": true + }, "@vitest/browser": { "optional": true }, @@ -8149,15 +8597,6 @@ }, "jsdom": { "optional": true - }, - "playwright": { - "optional": true - }, - "safaridriver": { - "optional": true - }, - "webdriverio": { - "optional": true } } }, @@ -8270,6 +8709,36 @@ "typescript": "*" } }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/w3c-xmlserializer/node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/webpack-sources": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", @@ -8283,6 +8752,40 @@ "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.1.tgz", "integrity": "sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg==" }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dev": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -8333,9 +8836,9 @@ } }, "node_modules/why-is-node-running": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", - "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, "dependencies": { "siginfo": "^2.0.0", @@ -8352,7 +8855,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -8370,7 +8872,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -8387,7 +8888,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -8395,14 +8895,12 @@ "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -8416,7 +8914,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -8428,7 +8925,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "engines": { "node": ">=12" }, @@ -8449,6 +8945,27 @@ "node": ">=14" } }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", @@ -8457,6 +8974,12 @@ "node": ">=12" } }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -8577,6 +9100,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/z-schema": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz", @@ -8636,13 +9171,13 @@ "license": "MIT", "dependencies": { "@kwai/config": "*", - "@vueuse/core": "^10.9.0", + "@vueuse/core": "11.0.3", "wretch": "^2.7.0", "zod": "^3.23.4" }, "devDependencies": { "vite-plugin-dts": "^3.6.3", - "vitest": "^0.34.6" + "vitest": "^2.0.5" } }, "packages/kwai-config": { @@ -8661,7 +9196,7 @@ "dayjs": "^1.11.10" }, "devDependencies": { - "vitest": "^0.34.6" + "vitest": "^2.0.5" } }, "packages/kwai-types": { @@ -8679,15 +9214,17 @@ "license": "MIT", "dependencies": { "@kwai/date": "*", - "@vuepic/vue-datepicker": "8.4.0", - "primevue": "^3.51.0" + "@vuepic/vue-datepicker": "9.0.3", + "primevue": "4.2.4" }, "devDependencies": { - "@tailwindcss/forms": "^0.5.6", - "@vitejs/plugin-vue": "^4.5.0", + "@tailwindcss/forms": "^0.5.9", + "@vitejs/plugin-vue": "^5.2.1", "autoprefixer": "^10.4.16", - "postcss": "^8.4.31", - "tailwindcss": "^3.4.3", + "postcss": "^8.4.49", + "postcss-import": "^16.1.0", + "tailwindcss": "^3.4.15", + "tailwindcss-primeui": "^0.3.4", "vite-plugin-dts": "^3.6.3", "vue": "3.4.25" }, @@ -8695,6 +9232,23 @@ "vee-validate": "^4.9.6", "vue-router": "^4.2.2" } + }, + "packages/kwai-ui/node_modules/postcss-import": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-16.1.0.tgz", + "integrity": "sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } } } } diff --git a/frontend/package.json b/frontend/package.json index 5ff6e4b14..c08571e87 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,26 +1,28 @@ { "name": "kwai", "version": "1.0.0", - "devDependencies": { - "@vue/test-utils": "^2.4.3", - "eslint-config-kwai": "*", - "msw": "^2.0.11", - "rollup-plugin-visualizer": "^5.11.0", - "syncpack": "^12.3.2", - "turbo": "^1.13.2", - "typescript": "^5.2.2", - "vite": "^4.5.3" - }, "engines": { "node": ">=18.0.0" }, "private": true, "scripts": { - "build": "turbo run build --force", - "dev": "turbo run dev --parallel --continue" + "test": "vitest", + "prebuild": "npm run build -w packages/kwai-types && npm run build -w packages/kwai-config && npm run build -w packages/kwai-date && npm run build -w packages/kwai-api && npm run build -w packages/kwai-ui", + "build": "npm run build --workspaces --if-present" }, "workspaces": [ "apps/*", "packages/*" - ] + ], + "devDependencies": { + "@go-task/cli": "^3.39.0", + "@vue/test-utils": "^2.4.3", + "eslint-config-kwai": "*", + "msw": "^2.0.11", + "rollup-plugin-visualizer": "^5.11.0", + "syncpack": "^12.3.2", + "typescript": "^5.2.2", + "vite": "^5.4.11", + "vitest": "^2.0.5" + } } diff --git a/frontend/packages/kwai-api/package.json b/frontend/packages/kwai-api/package.json index 005d63691..f70e0259b 100644 --- a/frontend/packages/kwai-api/package.json +++ b/frontend/packages/kwai-api/package.json @@ -4,13 +4,13 @@ "version": "0.0.1", "dependencies": { "@kwai/config": "*", - "@vueuse/core": "^10.9.0", + "@vueuse/core": "11.0.3", "wretch": "^2.7.0", "zod": "^3.23.4" }, "devDependencies": { "vite-plugin-dts": "^3.6.3", - "vitest": "^0.34.6" + "vitest": "^2.0.5" }, "exports": { ".": { diff --git a/frontend/packages/kwai-api/src/index.ts b/frontend/packages/kwai-api/src/index.ts index dc1f566d3..170790ee7 100644 --- a/frontend/packages/kwai-api/src/index.ts +++ b/frontend/packages/kwai-api/src/index.ts @@ -11,6 +11,7 @@ export const JsonResourceIdentifier = z.object({ id: z.optional(z.string()), type: z.string(), }); +export type JsonResourceIdentifierType = z.infer; export const JsonApiRelationship = z.object({ data: z.union([JsonResourceIdentifier, z.array(JsonResourceIdentifier)]), @@ -29,6 +30,16 @@ export const JsonApiData = JsonResourceIdentifier.extend({ }); export type JsonApiDataType = z.infer; +export const JsonApiError = z.object({ + status: z.string().default(''), + source: z.object({ + pointer: z.string(), + }).optional(), + title: z.string().default(''), + detail: z.string().default(''), +}); +export type JsonApiErrorType = z.infer; + export const JsonApiDocument = z.object({ meta: z.object({ count: z.number().optional(), @@ -37,9 +48,70 @@ export const JsonApiDocument = z.object({ }).optional(), data: z.union([JsonApiData, z.array(JsonApiData)]), included: z.array(JsonApiData).optional(), + errors: z.array(JsonApiError).optional(), }); export type JsonApiDocumentType = z.infer; +/** + * Transforms an array of resources in a nested object. + * + * This object makes it easier to lookup included resources. When, for example, a team resource + * has team members, the included array will contain resources for the team members but also + * country resources for the nationality of these team members. In this example, the returned + * object will have two properties: team_members and countries. The value of these properties will + * be another object with all the resources. The property for each resource will be the id of the resource. + * + * { + * team_members: { + * '1': { + * type: 'team_members', + * id: '1', + * attributes: { + * name: 'Jigoro Kano', + * }, + * relationships: { + * nationality: { + * data: { type: 'countries', 'id': '1' } + * } + * } + * } + * }, + * countries: { + * '1': { + * type: 'countries', + * id: '1', + * attributes: { + * name: 'Japan' + * } + * } + * } + * } + * + * @param resources + */ +export const transformResourceArrayToObject = (resources: JsonApiDataType[]): Record> => { + return resources.reduce((acc: Record>, current) => { + if (!acc[current.type]) { + acc[current.type] = {}; + } + acc[current.type][current.id as string] = current; + return acc; + }, {}); +}; + +/** + * An interface that can be used for the result of a transform of a document + * with multiple resources. + */ +export interface ResourceItems { + meta: { + count: number, + offset: number, + limit: number + }, + items: T[] +} + export interface LocalStorage { loginRedirect: Ref, accessToken: Ref, diff --git a/frontend/packages/kwai-config/vite.config.ts b/frontend/packages/kwai-config/vite.config.ts index 65b673dc6..46876f6c2 100644 --- a/frontend/packages/kwai-config/vite.config.ts +++ b/frontend/packages/kwai-config/vite.config.ts @@ -3,21 +3,24 @@ import dts from 'vite-plugin-dts'; import { defineConfig } from 'vite'; import { resolve } from 'path'; -export default defineConfig({ - plugins: [ - toml(), - dts({ copyDtsFiles: true }), - ], - build: { - lib: { - entry: resolve(__dirname, 'src/config.toml'), - name: '@kwai/config', - fileName: 'kwai-config', - }, - rollupOptions: { - output: { - exports: 'named', +export default defineConfig(({ mode }) => { + const configFile = mode === 'production' ? 'src/config.production.toml' : 'src/config.toml'; + return { + plugins: [ + toml(), + dts({ copyDtsFiles: true }), + ], + build: { + lib: { + entry: resolve(__dirname, configFile), + name: '@kwai/config', + fileName: 'kwai-config', + }, + rollupOptions: { + output: { + exports: 'named', + }, }, }, - }, + }; }); diff --git a/frontend/packages/kwai-date/package.json b/frontend/packages/kwai-date/package.json index 1f1fc7452..457322147 100644 --- a/frontend/packages/kwai-date/package.json +++ b/frontend/packages/kwai-date/package.json @@ -6,7 +6,7 @@ "dayjs": "^1.11.10" }, "devDependencies": { - "vitest": "^0.34.6" + "vitest": "^2.0.5" }, "exports": { ".": { diff --git a/frontend/packages/kwai-date/vitest.config.ts b/frontend/packages/kwai-date/vitest.config.ts index 7a05473e0..10db15723 100644 --- a/frontend/packages/kwai-date/vitest.config.ts +++ b/frontend/packages/kwai-date/vitest.config.ts @@ -1,6 +1,4 @@ -import { defineConfig } from "vitest/config" +import { defineConfig } from 'vitest/config'; export default defineConfig({ - test: { - } -}) +}); diff --git a/frontend/packages/kwai-ui/package.json b/frontend/packages/kwai-ui/package.json index b707191e3..1f60993c6 100644 --- a/frontend/packages/kwai-ui/package.json +++ b/frontend/packages/kwai-ui/package.json @@ -4,15 +4,17 @@ "version": "1.0.0", "dependencies": { "@kwai/date": "*", - "@vuepic/vue-datepicker": "8.4.0", - "primevue": "^3.51.0" + "@vuepic/vue-datepicker": "9.0.3", + "primevue": "4.2.4" }, "devDependencies": { - "@tailwindcss/forms": "^0.5.6", - "@vitejs/plugin-vue": "^4.5.0", + "@tailwindcss/forms": "^0.5.9", + "@vitejs/plugin-vue": "^5.2.1", "autoprefixer": "^10.4.16", - "postcss": "^8.4.31", - "tailwindcss": "^3.4.3", + "postcss": "^8.4.49", + "postcss-import": "^16.1.0", + "tailwindcss": "^3.4.15", + "tailwindcss-primeui": "^0.3.4", "vite-plugin-dts": "^3.6.3", "vue": "3.4.25" }, diff --git a/frontend/packages/kwai-ui/postcss.config.cjs b/frontend/packages/kwai-ui/postcss.config.cjs new file mode 100644 index 000000000..1ed1faa14 --- /dev/null +++ b/frontend/packages/kwai-ui/postcss.config.cjs @@ -0,0 +1,7 @@ +module.exports = { + plugins: [ + require('postcss-import'), + require('tailwindcss'), + require('autoprefixer'), + ], +}; diff --git a/frontend/packages/kwai-ui/postcss.config.js b/frontend/packages/kwai-ui/postcss.config.js deleted file mode 100644 index 9fcb8143f..000000000 --- a/frontend/packages/kwai-ui/postcss.config.js +++ /dev/null @@ -1,9 +0,0 @@ -import tailwind from 'tailwindcss' -import autoprefixer from 'autoprefixer' -import tailwindConfig from './tailwind.config.js' - -export default { - plugins: [ - tailwind(tailwindConfig), autoprefixer - ] -} diff --git a/frontend/packages/kwai-ui/src/alerts/Alert.vue b/frontend/packages/kwai-ui/src/alerts/Alert.vue index e41bf47ed..963b98a94 100644 --- a/frontend/packages/kwai-ui/src/alerts/Alert.vue +++ b/frontend/packages/kwai-ui/src/alerts/Alert.vue @@ -1,11 +1,23 @@ - - + + diff --git a/frontend/packages/kwai-ui/src/alerts/ErrorAlert.vue b/frontend/packages/kwai-ui/src/alerts/ErrorAlert.vue index 64e541614..362f510ec 100644 --- a/frontend/packages/kwai-ui/src/alerts/ErrorAlert.vue +++ b/frontend/packages/kwai-ui/src/alerts/ErrorAlert.vue @@ -1,15 +1,13 @@ + + - - diff --git a/frontend/packages/kwai-ui/src/alerts/InfoAlert.vue b/frontend/packages/kwai-ui/src/alerts/InfoAlert.vue index 89707302a..7ea0d5b44 100644 --- a/frontend/packages/kwai-ui/src/alerts/InfoAlert.vue +++ b/frontend/packages/kwai-ui/src/alerts/InfoAlert.vue @@ -1,15 +1,13 @@ + + - - diff --git a/frontend/packages/kwai-ui/src/alerts/LoadingAlert.vue b/frontend/packages/kwai-ui/src/alerts/LoadingAlert.vue index 67043fb50..d601003d4 100644 --- a/frontend/packages/kwai-ui/src/alerts/LoadingAlert.vue +++ b/frontend/packages/kwai-ui/src/alerts/LoadingAlert.vue @@ -1,13 +1,13 @@ + + - - diff --git a/frontend/packages/kwai-ui/src/alerts/WarningAlert.vue b/frontend/packages/kwai-ui/src/alerts/WarningAlert.vue index 421957095..c1ce94c3f 100644 --- a/frontend/packages/kwai-ui/src/alerts/WarningAlert.vue +++ b/frontend/packages/kwai-ui/src/alerts/WarningAlert.vue @@ -1,15 +1,13 @@ diff --git a/frontend/packages/kwai-ui/src/badges/KwaiBadge.vue b/frontend/packages/kwai-ui/src/badges/KwaiBadge.vue new file mode 100644 index 000000000..8aa258d63 --- /dev/null +++ b/frontend/packages/kwai-ui/src/badges/KwaiBadge.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/frontend/packages/kwai-ui/src/badges/KwaiTag.vue b/frontend/packages/kwai-ui/src/badges/KwaiTag.vue new file mode 100644 index 000000000..aa4709fb4 --- /dev/null +++ b/frontend/packages/kwai-ui/src/badges/KwaiTag.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/frontend/packages/kwai-ui/src/badges/index.ts b/frontend/packages/kwai-ui/src/badges/index.ts index 43d7097d4..b98d98d5b 100644 --- a/frontend/packages/kwai-ui/src/badges/index.ts +++ b/frontend/packages/kwai-ui/src/badges/index.ts @@ -1 +1,3 @@ +export { default as KwaiBadge } from './KwaiBadge.vue'; export { default as TextBadge } from './TextBadge.vue'; +export { default as KwaiTag } from './KwaiTag.vue'; diff --git a/frontend/packages/kwai-ui/src/card/KwaiCard.vue b/frontend/packages/kwai-ui/src/card/KwaiCard.vue new file mode 100644 index 000000000..b7dbba409 --- /dev/null +++ b/frontend/packages/kwai-ui/src/card/KwaiCard.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/frontend/packages/kwai-ui/src/card/KwaiPanel.vue b/frontend/packages/kwai-ui/src/card/KwaiPanel.vue new file mode 100644 index 000000000..51ec9a638 --- /dev/null +++ b/frontend/packages/kwai-ui/src/card/KwaiPanel.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/frontend/packages/kwai-ui/src/card/index.ts b/frontend/packages/kwai-ui/src/card/index.ts index 3177ca199..cdf8e8acf 100644 --- a/frontend/packages/kwai-ui/src/card/index.ts +++ b/frontend/packages/kwai-ui/src/card/index.ts @@ -2,3 +2,5 @@ export { default as CardRouterLinkedTitle } from './CardRouterLinkedTitle.vue'; export { default as CardLinkedTitle } from './CardLinkedTitle.vue'; export { default as CardTitle } from './CardTitle.vue'; export { default as Card } from './Card.vue'; +export { default as KwaiCard } from './KwaiCard.vue'; +export { default as KwaiPanel } from './KwaiPanel.vue'; diff --git a/frontend/packages/kwai-ui/src/css/primevue/accordion.css b/frontend/packages/kwai-ui/src/css/primevue/accordion.css new file mode 100644 index 000000000..11a13db0f --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/accordion.css @@ -0,0 +1,58 @@ +.p-accordionpanel { + @apply flex flex-col border-b border-surface-200 dark:border-surface-700 +} + +.p-accordionheader { + @apply cursor-pointer disabled:cursor-auto flex items-center justify-between p-[1.125rem] font-semibold + bg-surface-0 dark:bg-surface-900 + text-surface-500 dark:text-surface-400 + transition-colors duration-200 +} + +.p-accordionpanel:first-child > .p-accordionheader { + @apply rounded-ss-md rounded-se-md +} + +.p-accordionpanel:last-child > .p-accordionheader { + @apply rounded-ee-md rounded-es-md +} + +.p-accordionpanel:last-child.p-accordionpanel-active > .p-accordionheader { + @apply rounded-ee-md rounded-es-md +} + +.p-accordionheader-toggle-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-accordionpanel:not(.p-disabled) .p-accordionheader:focus-visible { + @apply outline outline-1 outline-offset-[-1px] outline-primary +} + +.p-accordionpanel:not(.p-accordionpanel-active):not(.p-disabled) > .p-accordionheader:hover { + @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 +} + +.p-accordionpanel:not(.p-accordionpanel-active):not(.p-disabled) .p-accordionheader:hover .p-accordionheader-toggle-icon { + @apply text-surface-700 dark:text-surface-0 +} + +.p-accordionpanel:not(.p-disabled).p-accordionpanel-active > .p-accordionheader { + @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 +} + +.p-accordionpanel:not(.p-disabled).p-accordionpanel-active > .p-accordionheader .p-accordionheader-toggle-icon { + @apply text-surface-700 dark:text-surface-0; +} + +.p-accordionpanel:not(.p-disabled).p-accordionpanel-active > .p-accordionheader:hover { + @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 +} + +.p-accordionpanel:not(.p-disabled).p-accordionpanel-active > .p-accordionheader:hover .p-accordionheader-toggle-icon { + @apply text-surface-700 dark:text-surface-0; +} + +.p-accordioncontent-content { + @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 pt-0 px-[1.125rem] pb-[1.125rem] +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/autocomplete.css b/frontend/packages/kwai-ui/src/css/primevue/autocomplete.css new file mode 100644 index 000000000..cb64d9833 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/autocomplete.css @@ -0,0 +1,143 @@ +@import './inputtext'; +@import './chip'; + +.p-autocomplete { + @apply inline-flex +} + +.p-autocomplete.p-disabled { + @apply opacity-100 +} + +.p-autocomplete-loader { + @apply absolute top-1/2 -mt-2 end-3 +} + +.p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-loader { + @apply end-[3.25rem] +} + +.p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-input { + @apply flex-auto w-[1%] +} + +.p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-input, +.p-autocomplete:has(.p-autocomplete-dropdown) .p-autocomplete-input-multiple { + @apply rounded-e-none +} + +.p-autocomplete-dropdown { + @apply cursor-pointer inline-flex items-center justify-center select-none overflow-hidden relative w-10 rounded-e-md + bg-surface-100 enabled:hover:bg-surface-200 enabled:active:bg-surface-300 + text-surface-600 enabled:hover:text-surface-700 enabled:hover:active:text-surface-800 + dark:bg-surface-800 dark:enabled:hover:bg-surface-700 dark:enabled:active:bg-surface-600 + dark:text-surface-300 dark:enabled:hover:text-surface-200 dark:enabled:active:text-surface-100 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary + transition-colors duration-200 +} + +.p-autocomplete .p-autocomplete-overlay { + @apply min-w-full +} + +.p-autocomplete-overlay { + @apply absolute top-0 left-0 rounded-md + bg-surface-0 dark:bg-surface-900 + border border-surface-200 dark:border-surface-700 + text-surface-700 dark:text-surface-0 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-autocomplete-list-container { + @apply overflow-auto +} + +.p-autocomplete-list { + @apply m-0 p-1 list-none flex flex-col gap-[2px] +} + +.p-autocomplete-option { + @apply cursor-pointer whitespace-nowrap relative overflow-hidden flex items-center px-3 py-2 rounded-sm + text-surface-700 dark:text-surface-0 bg-transparent border-none + transition-colors duration-200 +} + +.p-autocomplete-option:not(.p-autocomplete-option-selected):not(.p-disabled).p-focus { + @apply bg-surface-100 dark:bg-surface-800 text-surface-700 dark:text-surface-0 +} + +.p-autocomplete-option-selected { + @apply bg-highlight +} + +.p-autocomplete-option-selected.p-focus { + @apply bg-highlight-emphasis +} + +.p-autocomplete-option-group { + @apply m-0 px-3 py-2 text-surface-500 dark:text-surface-400 font-semibold bg-transparent +} + +.p-autocomplete-input-multiple { + @apply m-0 list-none cursor-text overflow-hidden flex items-center flex-wrap + px-3 py-1 gap-1 text-surface-700 dark:text-surface-0 bg-surface-0 dark:bg-surface-950 + border border-surface-300 dark:border-surface-700 rounded-md w-full + shadow-[0_1px_2px_0_rgba(18,18,23,0.05)] + transition-colors duration-200 outline-none +} + +.p-autocomplete:not(.p-disabled):hover .p-autocomplete-input-multiple { + @apply border-surface-400 dark:border-surface-600 +} + +.p-autocomplete:not(.p-disabled).p-focus .p-autocomplete-input-multiple { + @apply border-primary +} + +.p-autocomplete.p-invalid .p-autocomplete-input-multiple { + @apply border-red-400 dark:border-red-300 +} + +.p-variant-filled.p-autocomplete-input-multiple { + @apply bg-surface-50 dark:bg-surface-800 +} + +.p-autocomplete.p-disabled .p-autocomplete-input-multiple { + @apply opacity-100 cursor-default bg-surface-200 text-surface-500 dark:bg-surface-700 dark:text-surface-400 +} + +.p-autocomplete-chip.p-chip { + @apply py-1 rounded-sm +} + +.p-autocomplete-input-multiple:has(.p-autocomplete-chip) { + @apply px-1 +} + +.p-autocomplete-chip-item.p-focus .p-autocomplete-chip { + @apply bg-surface-200 text-surface-800 dark:bg-surface-700 dark:text-surface-0 +} + +.p-autocomplete-input-chip { + @apply flex-auto inline-flex py-1 +} + +.p-autocomplete-input-chip input { + @apply border-none outline-none bg-transparent m-0 p-0 shadow-none rounded-none w-full text-inherit +} + +.p-autocomplete-input-chip input::placeholder { + @apply text-surface-500 dark:text-surface-400 +} + +.p-autocomplete-empty-message { + @apply px-3 py-2 +} + +.p-autocomplete-fluid { + @apply flex +} + +.p-autocomplete-fluid:has(.p-autocomplete-dropdown) .p-autocomplete-input { + @apply w-[1%] +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/avatar.css b/frontend/packages/kwai-ui/src/css/primevue/avatar.css new file mode 100644 index 000000000..fde16bbb9 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/avatar.css @@ -0,0 +1,50 @@ +.p-avatar { + @apply inline-flex items-center justify-center + w-8 h-8 text-base rounded-md + bg-surface-200 dark:bg-surface-700 +} + +.p-avatar-image { + @apply bg-transparent +} + +.p-avatar-circle, +.p-avatar-circle img { + @apply rounded-full +} + +.p-avatar-icon { + @apply text-base +} + +.p-avatar img { + @apply w-full h-full +} + +.p-avatar-lg { + @apply w-12 h-12 text-2xl +} + +.p-avatar-lg .p-avatar-icon { + @apply text-2xl +} + +.p-avatar-xl { + @apply w-16 h-16 text-[2rem] +} + +.p-avatar-xl .p-avatar-icon { + @apply text-[2rem] +} + +.p-avatar-group { + @apply flex items-center +} + +.p-avatar-group .p-avatar + .p-avatar { + @apply -ms-4 +} + +.p-avatar-group .p-avatar { + @apply border-2 border-surface-200 dark:border-surface-700 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/badge.css b/frontend/packages/kwai-ui/src/css/primevue/badge.css new file mode 100644 index 000000000..7488458b4 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/badge.css @@ -0,0 +1,49 @@ +.p-badge { + @apply inline-flex items-center justify-center rounded-md + py-0 px-2 text-xs font-bold min-w-6 h-6 + bg-primary text-primary-contrast +} + +.p-badge-dot { + @apply min-w-2 h-2 rounded-full p-0 +} + +.p-badge-circle { + @apply p-0 rounded-full +} + +.p-badge-secondary { + @apply bg-surface-100 dark:bg-surface-800 text-surface-600 dark:text-surface-300 +} + +.p-badge-success { + @apply bg-green-500 dark:bg-green-400 text-white dark:text-green-950 +} + +.p-badge-info { + @apply bg-sky-500 dark:bg-sky-400 text-white dark:text-sky-950 +} + +.p-badge-warn { + @apply bg-orange-500 dark:bg-orange-400 text-white dark:text-orange-950 +} + +.p-badge-danger { + @apply bg-red-500 dark:bg-red-400 text-white dark:text-red-950 +} + +.p-badge-contrast { + @apply bg-surface-950 dark:bg-white text-white dark:text-surface-950 +} + +.p-badge-sm { + @apply text-[0.625rem] min-w-5 h-5 +} + +.p-badge-lg { + @apply text-sm min-w-7 h-7 +} + +.p-badge-xl { + @apply text-base min-w-8 h-8 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/blockui.css b/frontend/packages/kwai-ui/src/css/primevue/blockui.css new file mode 100644 index 000000000..bda54dbe1 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/blockui.css @@ -0,0 +1,15 @@ +.p-blockui { + @apply relative +} + +.p-blockui-mask { + @apply rounded-md +} + +.p-blockui-mask.p-overlay-mask { + @apply absolute +} + +.p-blockui-mask-document.p-overlay-mask { + @apply fixed +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/breadcrumb.css b/frontend/packages/kwai-ui/src/css/primevue/breadcrumb.css new file mode 100644 index 000000000..69beddf21 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/breadcrumb.css @@ -0,0 +1,41 @@ +.p-breadcrumb { + @apply bg-surface-0 dark:bg-surface-900 p-4 overflow-x-auto +} + +.p-breadcrumb-list { + @apply m-0 p-0 list-none flex items-center flex-nowrap gap-2 +} + +.p-breadcrumb-separator { + @apply flex items-center text-surface-400 dark:text-surface-500 +} + +.p-breadcrumb-separator-icon:dir(rtl) { + @apply rotate-180 +} + +.p-breadcrumb::-webkit-scrollbar { + @apply hidden +} + +.p-breadcrumb-item-link { + @apply no-underline flex items-center gap-2 transition-colors duration-200 rounded-md + text-surface-500 dark:text-surface-400 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-breadcrumb-item-link:hover .p-breadcrumb-item-label { + @apply text-surface-700 dark:text-surface-0 +} + +.p-breadcrumb-item-label { + @apply transition-colors duration-200 +} + +.p-breadcrumb-item-icon { + @apply text-surface-400 dark:text-surface-500 transition-colors duration-200 +} + +.p-breadcrumb-item-link:hover .p-breadcrumb-item-icon { + @apply text-surface-500 dark:text-surface-400 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/button.css b/frontend/packages/kwai-ui/src/css/primevue/button.css new file mode 100644 index 000000000..aafbc7692 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/button.css @@ -0,0 +1,333 @@ +@import './badge'; + +.p-button { + @apply inline-flex cursor-pointer select-none items-center justify-center overflow-hidden relative + bg-primary hover:bg-primary-emphasis active:bg-primary-emphasis-alt text-primary-contrast + border border-primary hover:border-primary-emphasis active:border-primary-emphasis-alt + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary + px-3 py-2 transition-colors duration-200 gap-2 rounded-md + disabled:cursor-default +} + +.p-button-icon-right { + @apply order-1 +} + +.p-button-icon-right:dir(rtl) { + @apply order-[-1] +} + +.p-button:not(.p-button-vertical) .p-button-icon:not(.p-button-icon-right):dir(rtl) { + @apply order-1 +} + +.p-button-icon-bottom { + @apply order-2 +} + +.p-button-icon-only { + @apply w-10 px-0 gap-0 +} + +.p-button-icon-only.p-button-rounded { + @apply rounded-full h-10 +} + +.p-button-icon-only .p-button-label { + @apply invisible w-0 +} + +.p-button-sm { + @apply text-sm px-[0.625rem] py-[0.375rem] +} + +.p-button-sm .p-button-icon { + @apply text-sm +} + +.p-button-lg { + @apply text-[1.125rem] px-[0.875rem] py-[0.625rem] +} + +.p-button-lg .p-button-icon { + @apply text-[1.125rem] +} + +.p-button-vertical { + @apply flex-col +} + +.p-button-label { + @apply font-medium +} + +.p-button-fluid { + @apply w-full +} + +.p-button-fluid.p-button-icon-only { + @apply w-10 +} + +.p-button .p-badge { + @apply min-w-4 h-4 leading-4 +} + +.p-button-raised { + @apply shadow-[0_3px_1px_-2px_rgba(0,0,0,0.2),0_2px_2px_0_rgba(0,0,0,0.14),0_1px_5px_0_rgba(0,0,0,0.12)] +} + +.p-button-rounded { + @apply rounded-[2rem] +} + +.p-button-secondary { + @apply bg-surface-100 hover:bg-surface-200 active:bg-surface-300 + border-surface-100 hover:border-surface-200 active:border-surface-300 + text-surface-600 hover:text-surface-700 active:text-surface-800 + dark:bg-surface-800 dark:hover:bg-surface-700 dark:active:bg-surface-600 + dark:border-surface-800 dark:hover:border-surface-700 dark:active:border-surface-600 + dark:text-surface-300 dark:hover:text-surface-200 dark:active:text-surface-100 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 + focus-visible:outline-surface-600 dark:focus-visible:outline-surface-300 +} + +.p-button-success { + @apply bg-green-500 hover:bg-green-600 active:bg-green-700 + border-green-500 hover:border-green-600 active:border-green-700 + text-white hover:text-white active:text-white + dark:bg-green-400 dark:hover:bg-green-300 dark:active:bg-green-200 + dark:border-green-400 dark:hover:border-green-300 dark:active:border-green-200 + dark:text-green-950 dark:hover:text-green-950 dark:active:text-green-950 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 + focus-visible:outline-green-500 dark:focus-visible:outline-green-400 +} + +.p-button-info { + @apply bg-sky-500 hover:bg-sky-600 active:bg-sky-700 + border-sky-500 hover:border-sky-600 active:border-sky-700 + text-white hover:text-white active:text-white + dark:bg-sky-400 dark:hover:bg-sky-300 dark:active:bg-sky-200 + dark:border-sky-400 dark:hover:border-sky-300 dark:active:border-sky-200 + dark:text-sky-950 dark:hover:text-sky-950 dark:active:text-sky-950 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 + focus-visible:outline-sky-500 dark:focus-visible:outline-sky-400 +} + +.p-button-warn { + @apply bg-orange-500 hover:bg-orange-600 active:bg-orange-700 + border-orange-500 hover:border-orange-600 active:border-orange-700 + text-white hover:text-white active:text-white + dark:bg-orange-400 dark:hover:bg-orange-300 dark:active:bg-orange-200 + dark:border-orange-400 dark:hover:border-orange-300 dark:active:border-orange-200 + dark:text-orange-950 dark:hover:text-orange-950 dark:active:text-orange-950 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 + focus-visible:outline-orange-500 dark:focus-visible:outline-orange-400 +} + +.p-button-help { + @apply bg-purple-500 hover:bg-purple-600 active:bg-purple-700 + border-purple-500 hover:border-purple-600 active:border-purple-700 + text-white hover:text-white active:text-white + dark:bg-purple-400 dark:hover:bg-purple-300 dark:active:bg-purple-200 + dark:border-purple-400 dark:hover:border-purple-300 dark:active:border-purple-200 + dark:text-purple-950 dark:hover:text-purple-950 dark:active:text-purple-950 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 + focus-visible:outline-purple-500 dark:focus-visible:outline-purple-400 +} + +.p-button-help { + @apply bg-purple-500 hover:bg-purple-600 active:bg-purple-700 + border-purple-500 hover:border-purple-600 active:border-purple-700 + text-white hover:text-white active:text-white + dark:bg-purple-400 dark:hover:bg-purple-300 dark:active:bg-purple-200 + dark:border-purple-400 dark:hover:border-purple-300 dark:active:border-purple-200 + dark:text-purple-950 dark:hover:text-purple-950 dark:active:text-purple-950 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 + focus-visible:outline-purple-500 dark:focus-visible:outline-purple-400 +} + +.p-button-danger { + @apply bg-red-500 hover:bg-red-600 active:bg-red-700 + border-red-500 hover:border-red-600 active:border-red-700 + text-white hover:text-white active:text-white + dark:bg-red-400 dark:hover:bg-red-300 dark:active:bg-red-200 + dark:border-red-400 dark:hover:border-red-300 dark:active:border-red-200 + dark:text-red-950 dark:hover:text-red-950 dark:active:text-red-950 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 + focus-visible:outline-red-500 dark:focus-visible:outline-red-400 +} + +.p-button-contrast { + @apply bg-surface-950 hover:bg-surface-900 active:bg-surface-800 + border-surface-950 hover:border-surface-900 active:border-surface-800 + text-white hover:text-white active:text-white + dark:bg-surface-0 dark:hover:bg-surface-100 dark:active:bg-surface-200 + dark:border-surface-100 dark:hover:border-surface-200 dark:active:border-surface-300 + dark:text-surface-950 dark:hover:text-surface-950 dark:active:text-surface-950 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 + focus-visible:outline-surface-950 dark:focus-visible:outline-surface-0 +} + +.p-button-outlined { + @apply bg-transparent hover:bg-primary-50 active:bg-primary-100 + border-primary-200 hover:border-primary-200 active:border-primary-200 + text-primary hover:text-primary active:text-primary + dark:bg-transparent dark:hover:bg-primary/5 dark:active:bg-primary/15 + dark:border-primary-700 dark:hover:border-primary-700 dark:active:border-primary-700 + dark:text-primary dark:hover:text-primary dark:active:text-primary +} + +.p-button-outlined.p-button-secondary { + @apply bg-transparent hover:bg-surface-50 active:bg-surface-100 + border-surface-200 hover:border-surface-200 active:border-surface-200 + text-surface-500 hover:text-surface-500 active:text-surface-500 + dark:bg-transparent dark:hover:bg-white/5 dark:active:bg-white/15 + dark:border-surface-700 dark:hover:border-surface-700 dark:active:border-surface-700 + dark:text-surface-400 dark:hover:text-surface-400 dark:active:text-surface-400 +} + +.p-button-outlined.p-button-success { + @apply bg-transparent hover:bg-green-50 active:bg-green-100 + border-green-200 hover:border-green-200 active:border-green-200 + text-green-500 hover:text-green-500 active:text-green-500 + dark:bg-transparent dark:hover:bg-green-400/5 dark:active:bg-green-400/15 + dark:border-green-700 dark:hover:border-green-700 dark:active:border-green-700 + dark:text-green-400 dark:hover:text-green-400 dark:active:text-green-400 +} + +.p-button-outlined.p-button-info { + @apply bg-transparent hover:bg-sky-50 active:bg-sky-100 + border-sky-200 hover:border-sky-200 active:border-sky-200 + text-sky-500 hover:text-sky-500 active:text-sky-500 + dark:bg-transparent dark:hover:bg-sky-400/5 dark:active:bg-sky-400/15 + dark:border-sky-700 dark:hover:border-sky-700 dark:active:border-sky-700 + dark:text-sky-400 dark:hover:text-sky-400 dark:active:text-sky-400 +} + +.p-button-outlined.p-button-warn { + @apply bg-transparent hover:bg-orange-50 active:bg-orange-100 + border-orange-200 hover:border-orange-200 active:border-orange-200 + text-orange-500 hover:text-orange-500 active:text-orange-500 + dark:bg-transparent dark:hover:bg-orange-400/5 dark:active:bg-orange-400/15 + dark:border-orange-700 dark:hover:border-orange-700 dark:active:border-orange-700 + dark:text-orange-400 dark:hover:text-orange-400 dark:active:text-orange-400 +} + +.p-button-outlined.p-button-help { + @apply bg-transparent hover:bg-purple-50 active:bg-purple-100 + border-purple-200 hover:border-purple-200 active:border-purple-200 + text-purple-500 hover:text-purple-500 active:text-purple-500 + dark:bg-transparent dark:hover:bg-purple-400/5 dark:active:bg-purple-400/15 + dark:border-purple-700 dark:hover:border-purple-700 dark:active:border-purple-700 + dark:text-purple-400 dark:hover:text-purple-400 dark:active:text-purple-400 +} + +.p-button-outlined.p-button-danger { + @apply bg-transparent hover:bg-red-50 active:bg-red-100 + border-red-200 hover:border-red-200 active:border-red-200 + text-red-500 hover:text-red-500 active:text-red-500 + dark:bg-transparent dark:hover:bg-red-400/5 dark:active:bg-red-400/15 + dark:border-red-700 dark:hover:border-red-700 dark:active:border-red-700 + dark:text-red-400 dark:hover:text-red-400 dark:active:text-red-400 +} + +.p-button-outlined.p-button-contrast { + @apply bg-transparent hover:bg-surface-50 active:bg-surface-100 + border-surface-700 hover:border-surface-700 active:border-surface-700 + text-surface-950 hover:text-surface-950 active:text-surface-950 + dark:bg-transparent dark:hover:bg-surface-800 dark:active:bg-surface-700 + dark:border-surface-500 dark:hover:border-surface-500 dark:active:border-surface-500 + dark:text-surface-0 dark:hover:text-surface-0 dark:active:text-surface-0 +} + +.p-button-outlined.p-button-plain { + @apply bg-transparent hover:bg-surface-50 active:bg-surface-100 + border-surface-200 hover:border-surface-200 active:border-surface-200 + text-surface-700 hover:text-surface-700 active:text-surface-700 + dark:bg-transparent dark:hover:bg-surface-800 dark:active:bg-surface-700 + dark:border-surface-600 dark:hover:border-surface-600 dark:active:border-surface-600 + dark:text-surface-0 dark:hover:text-surface-0 dark:active:text-surface-0 +} + +.p-button-text { + @apply bg-transparent hover:bg-primary-50 active:bg-primary-100 + border-transparent hover:border-transparent active:border-transparent + text-primary hover:text-primary active:text-primary + dark:bg-transparent dark:hover:bg-primary/5 dark:active:bg-primary/15 + dark:border-transparent dark:hover:border-transparent dark:active:border-transparent + dark:text-primary dark:hover:text-primary dark:active:text-primary +} + +.p-button-text.p-button-secondary { + @apply bg-transparent hover:bg-surface-50 active:bg-surface-100 + border-transparent hover:border-transparent active:border-transparent + text-surface-500 hover:text-surface-500 active:text-surface-500 + dark:bg-transparent dark:hover:bg-surface-800 dark:active:bg-surface-700 + dark:border-transparent dark:hover:border-transparent dark:active:border-transparent + dark:text-surface-400 dark:hover:text-surface-400 dark:active:text-surface-400 +} + +.p-button-text.p-button-success { + @apply bg-transparent hover:bg-green-50 active:bg-green-100 + border-transparent hover:border-transparent active:border-transparent + text-green-500 hover:text-green-500 active:text-green-500 + dark:bg-transparent dark:hover:bg-green-400/5 dark:active:bg-green-400/15 + dark:border-transparent dark:hover:border-transparent dark:active:border-transparent + dark:text-green-400 dark:hover:text-green-400 dark:active:text-green-400 +} + +.p-button-text.p-button-info { + @apply bg-transparent hover:bg-sky-50 active:bg-sky-100 + border-transparent hover:border-transparent active:border-transparent + text-sky-500 hover:text-sky-500 active:text-sky-500 + dark:bg-transparent dark:hover:bg-sky-400/5 dark:active:bg-sky-400/15 + dark:border-transparent dark:hover:border-transparent dark:active:border-transparent + dark:text-sky-400 dark:hover:text-sky-400 dark:active:text-sky-400 +} + +.p-button-text.p-button-warn { + @apply bg-transparent hover:bg-orange-50 active:bg-orange-100 + border-transparent hover:border-transparent active:border-transparent + text-orange-500 hover:text-orange-500 active:text-orange-500 + dark:bg-transparent dark:hover:bg-orange-400/5 dark:active:bg-orange-400/15 + dark:border-transparent dark:hover:border-transparent dark:active:border-transparent + dark:text-orange-400 dark:hover:text-orange-400 dark:active:text-orange-400 +} + +.p-button-text.p-button-help { + @apply bg-transparent hover:bg-purple-50 active:bg-purple-100 + border-transparent hover:border-transparent active:border-transparent + text-purple-500 hover:text-purple-500 active:text-purple-500 + dark:bg-transparent dark:hover:bg-purple-400/5 dark:active:bg-purple-400/15 + dark:border-transparent dark:hover:border-transparent dark:active:border-transparent + dark:text-purple-400 dark:hover:text-purple-400 dark:active:text-purple-400 +} + +.p-button-text.p-button-danger { + @apply bg-transparent hover:bg-red-50 active:bg-red-100 + border-transparent hover:border-transparent active:border-transparent + text-red-500 hover:text-red-500 active:text-red-500 + dark:bg-transparent dark:hover:bg-red-400/5 dark:active:bg-red-400/15 + dark:border-transparent dark:hover:border-transparent dark:active:border-transparent + dark:text-red-400 dark:hover:text-red-400 dark:active:text-red-400 +} + +.p-button-text.p-button-plain { + @apply bg-transparent hover:bg-surface-50 active:bg-surface-100 + border-transparent hover:border-transparent active:border-transparent + text-surface-700 hover:text-surface-700 active:text-surface-700 + dark:bg-transparent dark:hover:bg-surface-800 dark:active:bg-surface-700 + dark:border-transparent dark:hover:border-transparent dark:active:border-transparent + dark:text-surface-0 dark:hover:text-surface-0 dark:active:text-surface-0 +} + +.p-button-link { + @apply bg-transparent hover:bg-transparent active:bg-transparent + border-transparent hover:border-transparent active:border-transparent + text-primary hover:text-primary active:text-primary +} + +.p-button-link:not(:disabled):hover .p-button-label { + @apply underline +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/buttongroup.css b/frontend/packages/kwai-ui/src/css/primevue/buttongroup.css new file mode 100644 index 000000000..b5c888eef --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/buttongroup.css @@ -0,0 +1,19 @@ +.p-buttongroup .p-button { + @apply m-0 focus-visible:relative focus-visible:z-10 +} + +.p-buttongroup .p-button:not(:last-child) { + @apply border-r-0 +} + +.p-buttongroup .p-button:not(:first-of-type):not(:last-of-type) { + @apply rounded-none +} + +.p-buttongroup .p-button:first-of-type:not(:only-of-type) { + @apply rounded-e-none +} + +.p-buttongroup .p-button:last-of-type:not(:only-of-type) { + @apply rounded-s-none +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/card.css b/frontend/packages/kwai-ui/src/css/primevue/card.css new file mode 100644 index 000000000..45d8a6c51 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/card.css @@ -0,0 +1,22 @@ +.p-card { + @apply flex flex-col rounded-xl + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + shadow-[0_1px_3px_0_rgba(0,0,0,0.1),0_1px_2px_-1px_rgba(0,0,0,0.1)] +} + +.p-card-caption { + @apply flex flex-col gap-2 +} + +.p-card-body { + @apply p-5 flex flex-col gap-2 +} + +.p-card-title { + @apply font-medium text-xl +} + +.p-card-subtitle { + @apply text-surface-500 dark:text-surface-400 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/carousel.css b/frontend/packages/kwai-ui/src/css/primevue/carousel.css new file mode 100644 index 000000000..606a8b773 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/carousel.css @@ -0,0 +1,64 @@ +@import './button'; + +.p-carousel { + @apply flex flex-col +} + +.p-carousel-content-container { + @apply flex flex-col overflow-auto +} + +.p-carousel-content { + @apply flex flex-row gap-1 +} + +.p-carousel-content:dir(rtl) { + @apply flex-row-reverse +} + +.p-carousel-viewport { + @apply overflow-hidden w-full +} + +.p-carousel-item-list { + @apply flex flex-row +} + +.p-carousel-prev-button, +.p-carousel-next-button { + @apply self-center flex-shrink-0 +} + +.p-carousel-indicator-list { + @apply flex flex-row justify-center flex-wrap p-4 gap-2 m-0 list-none +} + +.p-carousel-indicator-list:dir(rtl) { + @apply rtl:flex-row-reverse +} + +.p-carousel-indicator-button { + @apply flex items-center justify-center w-8 h-2 border-none rounded-md p-0 m-0 select-none cursor-pointer transition-colors duration-200 + bg-surface-200 hover:bg-surface-300 dark:bg-surface-700 dark:hover:bg-surface-600 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-carousel-indicator-active .p-carousel-indicator-button { + @apply bg-primary +} + +.p-carousel-vertical .p-carousel-content { + @apply flex-col +} + +.p-carousel-vertical .p-carousel-item-list { + @apply flex-col h-full +} + +.p-items-hidden .p-carousel-item { + @apply invisible +} + +.p-items-hidden .p-carousel-item.p-carousel-item-active { + @apply visible +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/cascadeselect.css b/frontend/packages/kwai-ui/src/css/primevue/cascadeselect.css new file mode 100644 index 000000000..bcc29a55a --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/cascadeselect.css @@ -0,0 +1,169 @@ +.p-cascadeselect { + @apply inline-flex cursor-pointer relative select-none rounded-md + bg-surface-0 dark:bg-surface-950 + border border-surface-300 dark:border-surface-700 + shadow-[0_1px_2px_0_rgba(18,18,23,0.05)] + transition-colors duration-200 +} + +.p-cascadeselect:not(.p-disabled):hover { + @apply border-surface-400 dark:border-surface-600 +} + +.p-cascadeselect:not(.p-disabled).p-focus { + @apply border-primary +} + +.p-cascadeselect.p-variant-filled { + @apply bg-surface-50 dark:bg-surface-800 +} + +.p-cascadeselect.p-invalid { + @apply border-red-400 dark:border-red-300 +} + +.p-cascadeselect.p-disabled { + @apply bg-surface-200 text-surface-500 dark:bg-surface-700 dark:text-surface-400 opacity-100 cursor-default +} + +.p-cascadeselect-dropdown { + @apply flex items-center justify-center shrink-0 bg-transparent + text-surface-500 dark:text-surface-400 w-10 rounded-e-md +} + +.p-cascadeselect-label { + @apply block whitespace-nowrap overflow-hidden flex-auto w-[1%] + py-2 px-3 overflow-ellipsis + text-surface-700 dark:text-surface-0 bg-transparent border-none outline-none +} + +.p-cascadeselect-label.p-placeholder { + @apply text-surface-500 dark:text-surface-400 +} + +.p-cascadeselect-clearable .p-cascadeselect-label { + @apply pe-7 +} + +.p-cascadeselect.p-disabled .p-cascadeselect-label { + @apply text-surface-500 dark:text-surface-400 +} + +.p-cascadeselect-label-empty { + @apply overflow-hidden opacity-0 +} + +.p-cascadeselect-fluid { + @apply flex +} + +.p-cascadeselect-fluid .p-cascadeselect-label { + @apply w-[1%] +} + +.p-cascadeselect-overlay { + @apply absolute top-0 left-0 rounded-md + bg-surface-0 dark:bg-surface-900 + border border-surface-200 dark:border-surface-700 + text-surface-700 dark:text-surface-0 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-cascadeselect .p-cascadeselect-overlay { + @apply min-w-full +} + +.p-cascadeselect-option-list { + @apply hidden min-w-full absolute z-10 +} + +.p-cascadeselect-list { + @apply min-w-full m-0 list-none p-1 flex flex-col gap-[2px] +} + +.p-cascadeselect-option { + @apply cursor-pointer font-normal whitespace-nowrap + text-surface-700 dark:text-surface-0 bg-transparent border-none + transition-colors duration-200 rounded-sm +} + +.p-cascadeselect-option-active { + @apply overflow-visible +} + +.p-cascadeselect-option-active > .p-cascadeselect-option-content { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-cascadeselect-option:not(.p-cascadeselect-option-selected):not(.p-disabled).p-focus > .p-cascadeselect-option-content { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-cascadeselect-option:not(.p-cascadeselect-option-selected):not(.p-disabled).p-focus .p-cascadeselect-group-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-cascadeselect-option-selected .p-cascadeselect-option-content { + @apply bg-highlight +} + +.p-cascadeselect-option-selected.p-focus { + @apply bg-highlight-emphasis +} + +.p-cascadeselect-option-active > .p-cascadeselect-option-list { + @apply block start-full top-0 +} + +.p-cascadeselect-option-content { + @apply flex items-center justify-between overflow-hidden relative px-3 py-2 +} + +.p-cascadeselect-group-icon { + @apply text-sm w-[0.875rem] h-[0.875rem] text-surface-400 dark:text-surface-500 +} + +.p-cascadeselect-group-icon:dir(rtl) { + @apply rotate-180 +} + + +.p-cascadeselect-mobile-active .p-cascadeselect-option-content { + @apply rounded-sm +} + +.p-cascadeselect-mobile-active-active .p-cascadeselect-list { + @apply flex flex-col top-full start-0 z-10 +} + +.p-cascadeselect-mobile-active .p-cascadeselect-list > .p-cascadeselect-option > .p-cascadeselect-option-content .p-cascadeselect-group-icon { + @apply ms-auto transition-transform duration-200 +} + +.p-cascadeselect-mobile-active .p-cascadeselect-list .p-cascadeselect-group-icon { + @apply transition-transform duration-200 rotate-90 +} + +.p-cascadeselect-mobile-active .p-cascadeselect-option-active > .p-cascadeselect-option-content .p-cascadeselect-group-icon { + @apply -rotate-90 +} + +.p-cascadeselect-mobile-active .p-cascadeselect-option-list { + @apply static shadow-none border-none ps-4 +} + +.p-cascadeselect-sm .p-cascadeselect-label { + @apply text-sm px-[0.625rem] py-[0.375rem] +} + +.p-cascadeselect-sm .p-cascadeselect-dropdown .p-icon { + @apply text-sm w-[0.875rem] h-[0.875rem] +} + +.p-cascadeselect-lg .p-cascadeselect-label { + @apply text-lg px-[0.875rem] py-[0.625rem] +} + +.p-cascadeselect-lg .p-cascadeselect-dropdown .p-icon { + @apply text-lg w-[1.125rem] h-[1.125rem] +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/checkbox.css b/frontend/packages/kwai-ui/src/css/primevue/checkbox.css new file mode 100644 index 000000000..431fbbd6b --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/checkbox.css @@ -0,0 +1,84 @@ +.p-checkbox { + @apply relative inline-flex select-none w-5 h-5 align-bottom +} + +.p-checkbox-input { + @apply cursor-pointer disabled:cursor-default appearance-none absolute start-0 top-0 w-full h-full m-0 p-0 opacity-0 z-10 + border border-transparent rounded-sm +} + +.p-checkbox-box { + @apply flex justify-center items-center rounded-sm w-5 h-5 + border border-surface-300 dark:border-surface-700 + bg-surface-0 dark:bg-surface-950 + transition-colors duration-200 + shadow-[0_1px_2px_0_rgba(18,18,23,0.05)] +} + +.p-checkbox-icon { + @apply text-surface-700 dark:text-surface-0 + text-sm w-[0.875rem] h-[0.875rem] + transition-colors duration-200 +} + +.p-checkbox:not(.p-disabled):has(.p-checkbox-input:hover) .p-checkbox-box { + @apply border-surface-400 dark:border-surface-600 +} + +.p-checkbox-checked .p-checkbox-box { + @apply border-primary bg-primary +} + +.p-checkbox-checked .p-checkbox-icon { + @apply text-primary-contrast +} + +.p-checkbox-checked:not(.p-disabled):has(.p-checkbox-input:hover) .p-checkbox-box { + @apply bg-primary-emphasis border-primary-emphasis +} + +.p-checkbox-checked:not(.p-disabled):has(.p-checkbox-input:hover) .p-checkbox-icon { + @apply text-primary-contrast +} + +.p-checkbox:not(.p-disabled):has(.p-checkbox-input:focus-visible) .p-checkbox-box { + @apply outline outline-1 outline-offset-2 outline-primary +} + +.p-checkbox.p-invalid > .p-checkbox-box { + @apply border-red-400 dark:border-red-300 +} + +.p-checkbox.p-variant-filled .p-checkbox-box { + @apply bg-surface-50 dark:bg-surface-800 +} + +.p-checkbox.p-disabled { + @apply opacity-100 +} + +.p-checkbox.p-disabled .p-checkbox-box { + @apply bg-surface-200 dark:bg-surface-400 border-surface-300 dark:border-surface-700 +} + +.p-checkbox.p-disabled .p-checkbox-box .p-checkbox-icon { + @apply text-surface-700 dark:text-surface-400 +} + +.p-checkbox-sm, +.p-checkbox-sm .p-checkbox-box { + @apply w-4 h-4 +} + +.p-checkbox-sm .p-checkbox-icon { + @apply w-3 h-3 +} + +.p-checkbox-lg, +.p-checkbox-lg .p-checkbox-box { + @apply w-6 h-6 +} + +.p-checkbox-lg .p-checkbox-icon { + @apply w-4 h-4 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/chip.css b/frontend/packages/kwai-ui/src/css/primevue/chip.css new file mode 100644 index 000000000..7f10d74ed --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/chip.css @@ -0,0 +1,27 @@ +.p-chip { + @apply inline-flex items-center rounded-2xl gap-2 px-3 py-2 + bg-surface-100 dark:bg-surface-800 + text-surface-800 dark:text-surface-0 +} + +.p-chip-icon { + @apply text-surface-800 dark:bg-surface-0 text-base w-4 h-4 +} + +.p-chip-image { + @apply rounded-full w-8 h-8 -ms-2 +} + +.p-chip:has(.p-chip-remove-icon) { + @apply pe-2 +} + +.p-chip:has(.p-chip-image) { + @apply pt-1 pb-1 +} + +.p-chip-remove-icon { + @apply cursor-pointer text-base w-4 h-4 rounded-full + text-surface-800 dark:text-surface-0 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/colorpicker.css b/frontend/packages/kwai-ui/src/css/primevue/colorpicker.css new file mode 100644 index 000000000..71c433548 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/colorpicker.css @@ -0,0 +1,47 @@ +.p-colorpicker { + @apply inline-block relative; +} + +.p-colorpicker-dragging { + @apply cursor-pointer +} + +.p-colorpicker-preview { + @apply w-6 h-6 p-0 border-none rounded-md transition-colors duration-200 cursor-pointer disabled:cursor-auto + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-colorpicker-panel { + @apply bg-surface-800 dark:bg-surface-900 + border border-surface-900 dark:border-surface-700 + rounded-md shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] + w-[193px] h-[166px] absolute top-0 start-0 +} + +.p-colorpicker-panel-inline { + @apply static shadow-none +} + +.p-colorpicker-content { + @apply relative; +} + +.p-colorpicker-color-selector { + @apply w-[150px] h-[150px] top-[8px] start-[8px] absolute +} + +.p-colorpicker-color-background { + @apply w-full h-full bg-[linear-gradient(to_top,#000_0%,rgba(0,0,0,0)_100%),linear-gradient(to_right,#fff_0%,rgba(255,255,255,0)_100%)]; +} + +.p-colorpicker-color-handle { + @apply absolute top-0 start-[150px] rounded-full w-[10px] h-[10px] border border-surface-0 -mt-[5px] me-0 mb-0 -ms-[5px] cursor-pointer opacity-85 +} + +.p-colorpicker-hue { + @apply w-[17px] h-[150px] top-[8px] start-[167px] absolute opacity-85 bg-[linear-gradient(0deg,red_0,#ff0_17%,#0f0_33%,#0ff_50%,#00f_67%,#f0f_83%,red)]; +} + +.p-colorpicker-hue-handle { + @apply absolute top-[150px] start-0 w-[21px] -ms-[2px] -mt-[5px] h-[10px] border-2 opacity-85 border-surface-0 cursor-pointer +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/common.css b/frontend/packages/kwai-ui/src/css/primevue/common.css new file mode 100644 index 000000000..8a388600e --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/common.css @@ -0,0 +1,81 @@ +.p-connected-overlay-enter-from { + @apply opacity-0 scale-y-75 +} + +.p-connected-overlay-leave-to { + @apply opacity-0 +} + +.p-connected-overlay-enter-active { + @apply transition-[opacity,transform] duration-150 ease-[cubic-bezier(0,0,0.2,1)] +} + +.p-connected-overlay-leave-active { + @apply transition-opacity duration-100 ease-linear +} + +.p-toggleable-content-enter-from, +.p-toggleable-content-leave-to { + @apply max-h-0 +} + +.p-toggleable-content-enter-to, +.p-toggleable-content-leave-from { + @apply max-h-[1000px] +} + +.p-toggleable-content-leave-active { + @apply overflow-hidden transition-[max-height] duration-[450ms] ease-[cubic-bezier(0,1,0,1)]; +} + +.p-toggleable-content-enter-active { + @apply overflow-hidden transition-[max-height] duration-1000 ease-in-out +} + +.p-disabled, +.p-disabled * { + @apply cursor-default pointer-events-none select-none +} + +.p-disabled, +.p-component:disabled { + @apply opacity-60 +} + +.pi { + @apply text-base +} + +.p-icon { + @apply w-4 h-4 +} + +.p-overlay-mask { + @apply bg-black/50 text-surface-200 transition-colors duration-150 fixed top-0 start-0 w-full h-full +} + +.p-overlay-mask-enter { + animation: p-overlay-mask-enter-animation 150ms forwards; +} + +.p-overlay-mask-leave { + animation: p-overlay-mask-leave-animation 150ms forwards; +} + +@keyframes p-overlay-mask-enter-animation { + from { + background: transparent; + } + to { + background: rgba(0,0,0,0.5); + } +} + +@keyframes p-overlay-mask-leave-animation { + from { + background: rgba(0,0,0,0.5); + } + to { + background: transparent; + } +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/confirmdialog.css b/frontend/packages/kwai-ui/src/css/primevue/confirmdialog.css new file mode 100644 index 000000000..d28074ddb --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/confirmdialog.css @@ -0,0 +1,10 @@ +@import './dialog'; +@import './button'; + +.p-confirmdialog .p-dialog-content { + @apply flex items-center gap-4 +} + +.p-confirmdialog-icon { + @apply text-surface-700 dark:text-surface-0 text-[2rem] h-8 w-8 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/confirmpopup.css b/frontend/packages/kwai-ui/src/css/primevue/confirmpopup.css new file mode 100644 index 000000000..861a29494 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/confirmpopup.css @@ -0,0 +1,66 @@ +@import './button'; + +.p-confirmpopup { + @apply absolute mt-[10px] top-0 left-0 + border border-surface-200 dark:border-surface-700 rounded-md + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] + before:bottom-full before:left-5 before:h-0 before:w-0 before:absolute before:pointer-events-none + before:border-[10px] before:-ms-[10px] before:border-transparent before:border-b-surface-200 dark:before:border-b-surface-700 + after:bottom-full after:left-5 after:h-0 after:w-0 after:absolute after:pointer-events-none + after:border-[8px] after:-ms-[8px] after:border-transparent after:border-b-surface-0 dark:after:border-b-surface-900 +} + +.p-confirmpopup-content { + @apply flex items-center p-3 gap-4 +} + +.p-confirmpopup-icon { + @apply text-2xl w-6 h-6 text-surface-700 dark:text-surface-0 +} + +.p-confirmpopup-footer { + @apply flex justify-end gap-2 pt-0 px-3 pb-3 +} + +.p-confirmpopup-footer button { + @apply w-auto +} + +.p-confirmpopup-footer button:last-child { + @apply m-0 +} + +.p-confirmpopup-flipped { + @apply -mt-[10px] mb-[10px] +} + +.p-confirmpopup-enter-from { + @apply opacity-0 scale-y-75 +} + +.p-confirmpopup-leave-to { + @apply opacity-0 +} + +.p-confirmpopup-enter-active { + @apply [transition:transform_120ms_cubic-bezier(0,0,0.2,1),opacity_120ms_cubic-bezier(0,0,0.2,1)] +} + +.p-confirmpopup-leave-active { + @apply transition-opacity duration-100 ease-linear +} + +.p-confirmpopup-flipped:after, +.p-confirmpopup-flipped:before { + @apply bottom-auto top-full +} + +.p-confirmpopup-flipped:after { + @apply border-b-transparent border-t-surface-0 dark:border-t-surface-900 +} + +.p-confirmpopup-flipped:before { + @apply border-b-transparent border-t-surface-200 dark:border-t-surface-700 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/contextmenu.css b/frontend/packages/kwai-ui/src/css/primevue/contextmenu.css new file mode 100644 index 000000000..d9af2908b --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/contextmenu.css @@ -0,0 +1,101 @@ +.p-contextmenu { + @apply bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + border border-surface-200 dark:border-surface-700 + rounded-md min-w-52 shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-contextmenu-root-list, +.p-contextmenu-submenu { + @apply m-0 p-1 list-none outline-none flex flex-col gap-[2px] +} + +.p-contextmenu-submenu { + @apply absolute min-w-full z-10 rounded-md + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + border border-surface-200 dark:border-surface-700 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-contextmenu-item { + @apply relative +} + +.p-contextmenu-item-content { + @apply transition-colors duration-200 rounded-sm text-surface-700 dark:text-surface-0 +} + +.p-contextmenu-item-link { + @apply cursor-pointer flex items-center no-underline overflow-hidden relative text-inherit + px-3 py-2 gap-2 select-none outline-none +} + +.p-contextmenu-item-icon { + @apply text-surface-400 dark:text-surface-500 +} + +.p-contextmenu-submenu-icon { + @apply text-surface-400 dark:text-surface-500 ms-auto text-sm w-[0.875rem] h-[0.875rem] +} + +.p-contextmenu-item.p-focus > .p-contextmenu-item-content { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-contextmenu-item.p-focus > .p-contextmenu-item-content .p-contextmenu-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-contextmenu-item.p-focus > .p-contextmenu-item-content .p-contextmenu-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-contextmenu-item:not(.p-disabled) > .p-contextmenu-item-content:hover { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-contextmenu-item:not(.p-disabled) > .p-contextmenu-item-content:hover .p-contextmenu-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-contextmenu-item:not(.p-disabled) > .p-contextmenu-item-content:hover .p-contextmenu-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-contextmenu-item-active > .p-contextmenu-item-content { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-contextmenu-item-active > .p-contextmenu-item-content .p-contextmenu-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-contextmenu-item-active > .p-contextmenu-item-content .p-contextmenu-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-contextmenu-separator { + @apply border-t border-surface-200 dark:border-surface-700 +} + +.p-contextmenu-enter-from, +.p-contextmenu-leave-active { + @apply opacity-0 +} + +.p-contextmenu-enter-active { + @apply transition-opacity duration-[250ms] +} + +.p-contextmenu-mobile .p-contextmenu-submenu { + @apply static shadow-none border-none ps-4 pe-0 +} + +.p-contextmenu-mobile .p-contextmenu-submenu-icon { + @apply transition-transform duration-200 rotate-90 +} + +.p-contextmenu-mobile .p-contextmenu-item-active > .p-contextmenu-item-content .p-contextmenu-submenu-icon { + @apply -rotate-90 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/datatable.css b/frontend/packages/kwai-ui/src/css/primevue/datatable.css new file mode 100644 index 000000000..b77d71d2a --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/datatable.css @@ -0,0 +1,408 @@ +@import './paginator'; + +.p-datatable { + @apply relative +} + +.p-datatable-table { + @apply border-spacing-0 w-full +} + +.p-datatable-scrollable > .p-datatable-table-container { + @apply relative +} + +.p-datatable-scrollable-table > .p-datatable-thead { + @apply top-0 z-10 +} + +.p-datatable-scrollable-table > .p-datatable-frozen-tbody { + @apply sticky z-10 +} + +.p-datatable-scrollable-table > .p-datatable-tfoot { + @apply bottom-0 z-10 +} + +.p-datatable-scrollable .p-datatable-frozen-column { + @apply sticky bg-surface-0 dark:bg-surface-900 +} + +.p-datatable-scrollable th.p-datatable-frozen-column { + @apply z-10 +} + +.p-datatable-scrollable > .p-datatable-table-container > .p-datatable-table > .p-datatable-thead, +.p-datatable-scrollable > .p-datatable-table-container > .p-virtualscroller > .p-datatable-table > .p-datatable-thead { + @apply bg-surface-0 dark:bg-surface-900 +} + +.p-datatable-scrollable > .p-datatable-table-container > .p-datatable-table > .p-datatable-tfoot, +.p-datatable-scrollable > .p-datatable-table-container > .p-virtualscroller > .p-datatable-table > .p-datatable-tfoot { + @apply bg-surface-0 dark:bg-surface-900 +} + +.p-datatable-flex-scrollable { + @apply flex flex-col h-full +} + +.p-datatable-flex-scrollable > .p-datatable-table-container { + @apply flex flex-col flex-1 h-full +} + +.p-datatable-scrollable-table > .p-datatable-tbody > .p-datatable-row-group-header { + @apply sticky z-10 +} + +.p-datatable-resizable-table > .p-datatable-thead > tr > th, +.p-datatable-resizable-table > .p-datatable-tfoot > tr > td, +.p-datatable-resizable-table > .p-datatable-tbody > tr > td { + @apply overflow-hidden whitespace-nowrap +} + +.p-datatable-resizable-table > .p-datatable-thead > tr > th.p-datatable-resizable-column:not(.p-datatable-frozen-column) { + @apply bg-clip-padding relative +} + +.p-datatable-resizable-table-fit > .p-datatable-thead > tr > th.p-datatable-resizable-column:last-child .p-datatable-column-resizer { + @apply hidden +} + +.p-datatable-column-resizer { + @apply block absolute top-0 end-0 m-0 w-2 h-full p-0 cursor-col-resize border border-transparent +} + +.p-datatable-column-header-content { + @apply flex items-center gap-2 +} + +.p-datatable-column-resize-indicator { + @apply w-px absolute z-10 hidden bg-primary +} + +.p-datatable-row-reorder-indicator-up, +.p-datatable-row-reorder-indicator-down { + @apply absolute hidden +} + +.p-datatable-reorderable-column, +.p-datatable-reorderable-row-handle { + @apply cursor-move +} + +.p-datatable-mask { + @apply absolute flex items-center justify-center z-20 +} + +.p-datatable-inline-filter { + @apply flex items-center w-full gap-2 +} + +.p-datatable-inline-filter .p-datatable-filter-element-container { + @apply flex-auto w-[1%] +} + +.p-datatable-filter-overlay { + @apply bg-surface-0 dark:bg-surface-900 rounded-md min-w-52 + border border-surface-200 dark:border-surface-700 + text-surface-700 dark:text-surface-0 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-datatable-filter-constraint-list { + @apply m-0 list-none flex flex-col p-1 gap-[2px] +} + +.p-datatable-filter-constraint { + @apply px-3 py-2 rounded-sm cursor-pointer transition-colors duration-200 text-surface-700 dark:text-surface-0 +} + +.p-datatable-filter-constraint-selected { + @apply bg-highlight +} + +.p-datatable-filter-constraint:not(.p-datatable-filter-constraint-selected):not(.p-disabled):hover +{ + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-datatable-filter-constraint:focus-visible { + @apply outline-none bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-datatable-filter-constraint-selected:focus-visible { + @apply bg-highlight-emphasis +} + +.p-datatable-filter-constraint-separator { + @apply border-t border-surface-200 dark:border-surface-700 +} + +.p-datatable-popover-filter { + @apply inline-flex ms-auto +} + +.p-datatable-filter-overlay-popover { + @apply flex flex-col gap-2 + bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 + border border-surface-200 dark:border-surface-700 rounded-md p-3 min-w-52 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-datatable-filter-operator-dropdown { + @apply w-full +} + +.p-datatable-filter-rule-list, +.p-datatable-filter-rule { + @apply flex flex-col gap-2 +} + +.p-datatable-filter-rule { + @apply border-b border-surface-200 dark:border-surface-700 last:border-b-0 pb-2 last:pb-0 +} + +.p-datatable-filter-add-rule-button { + @apply w-full +} + +.p-datatable-filter-remove-rule-button { + @apply w-full +} + +.p-datatable-filter-buttonbar { + @apply p-0 flex items-center justify-between +} + +.p-datatable-virtualscroller-spacer { + @apply flex +} + +.p-datatable .p-virtualscroller .p-virtualscroller-loading { + @apply transform-none min-h-0 sticky top-0 start-0 +} + +.p-datatable-paginator-top { + @apply border-b border-surface-200 dark:border-surface-700 +} + +.p-datatable-paginator-bottom { + @apply border-t border-surface-200 dark:border-surface-700 +} + +.p-datatable-header { + @apply py-3 px-4 border-b border-surface-200 dark:border-surface-700 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 +} + +.p-datatable-footer { + @apply py-3 px-4 border-b border-surface-200 dark:border-surface-700 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 +} + +.p-datatable-header-cell { + @apply py-3 px-4 font-normal text-start transition-colors duration-200 + border-b border-surface-200 dark:border-surface-700 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 +} + +.p-datatable-column-title { + @apply font-semibold +} + +.p-datatable-tbody > tr { + @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 transition-colors duration-200 +} + +.p-datatable-tbody > tr > td { + @apply text-start py-3 px-4 border-b border-surface-200 dark:border-surface-800 +} + +.p-datatable-hoverable .p-datatable-tbody > tr:not(.p-datatable-row-selected):hover { + @apply bg-surface-100 text-surface-800 dark:bg-surface-800 dark:text-surface-0 +} + +.p-datatable-tbody > tr.p-datatable-row-selected { + @apply bg-highlight +} + +.p-datatable-tbody > tr:has(+ .p-datatable-row-selected) > td { + @apply border-b-primary-100 dark:border-b-primary-900 +} + +.p-datatable-tbody > tr.p-datatable-row-selected > td { + @apply border-b-primary-100 dark:border-b-primary-900 +} + +.p-datatable-tbody > tr:focus-visible, +.p-datatable-tbody > tr.p-datatable-contextmenu-row-selected { + @apply outline outline-1 -outline-offset-1 outline-primary +} + +.p-datatable-tfoot > tr > td { + @apply text-start py-3 px-4 border-b border-surface-200 dark:border-surface-800 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 +} + +.p-datatable-column-footer { + @apply font-semibold +} + +.p-datatable-sortable-column { + @apply cursor-pointer select-none focus-visible:outline focus-visible:outline-1 focus-visible:-outline-offset-1 focus-visible:outline-primary +} + +.p-datatable-column-title, +.p-datatable-sort-icon, +.p-datatable-sort-badge { + @apply align-middle +} + +.p-datatable-sort-icon { + @apply text-surface-500 dark:text-surface-400 transition-colors duration-200 +} + +.p-datatable-sortable-column:not(.p-datatable-column-sorted):hover { + @apply bg-surface-100 text-surface-800 dark:bg-surface-800 dark:text-surface-0 +} + +.p-datatable-sortable-column:not(.p-datatable-column-sorted):hover .p-datatable-sort-icon { + @apply text-surface-600 dark:text-surface-300 +} + +.p-datatable-column-sorted { + @apply bg-highlight +} + +.p-datatable-column-sorted .p-datatable-sort-icon { + @apply bg-highlight +} + +.p-datatable-hoverable .p-datatable-selectable-row { + @apply cursor-pointer +} + +.p-datatable-tbody > tr.p-datatable-dragpoint-top > td { + @apply shadow-[inset_0_2px_0_0_theme(colors.primary)] +} + +.p-datatable-tbody > tr.p-datatable-dragpoint-bottom > td { + @apply shadow-[inset_0_-2px_0_0_theme(colors.primary)] +} + +.p-datatable-loading-icon { + @apply text-[2rem] w-8 h-8 +} + +.p-datatable-gridlines .p-datatable-header { + @apply border-t border-x +} + +.p-datatable-gridlines .p-datatable-footer { + @apply border-b border-x +} + +.p-datatable-gridlines .p-datatable-paginator-top { + @apply border-t border-x +} + +.p-datatable-gridlines .p-datatable-paginator-bottom { + @apply border-b border-x +} + +.p-datatable-gridlines .p-datatable-thead > tr > th { + @apply border-t border-x last:border +} + +.p-datatable-gridlines .p-datatable-tbody > tr > td { + @apply border-t border-s last:border-r +} + +.p-datatable-gridlines .p-datatable-tbody > tr:last-child > td { + @apply border-y border-s last:border +} + +.p-datatable-gridlines .p-datatable-tfoot > tr > td { + @apply border-y border-s last:border +} + +.p-datatable.p-datatable-gridlines .p-datatable-thead + .p-datatable-tfoot > tr > td { + @apply border-b border-s last:border-r +} + +.p-datatable.p-datatable-gridlines:has(.p-datatable-thead):has(.p-datatable-tbody) .p-datatable-tbody > tr > td { + @apply border-b border-s last:border-r +} + +.p-datatable.p-datatable-gridlines:has(.p-datatable-tbody):has(.p-datatable-tfoot) .p-datatable-tbody > tr:last-child > td { + @apply border-s last:border-r +} + +.p-datatable.p-datatable-striped .p-datatable-tbody > tr.p-row-odd { + @apply bg-surface-50 dark:bg-surface-950 +} + +.p-datatable.p-datatable-striped .p-datatable-tbody > tr.p-row-odd.p-datatable-row-selected { + @apply bg-highlight +} + +.p-datatable.p-datatable-sm .p-datatable-header { + @apply py-1 px-2 +} + +.p-datatable.p-datatable-sm .p-datatable-thead > tr > th { + @apply py-1 px-2 +} + +.p-datatable.p-datatable-sm .p-datatable-tbody > tr > td { + @apply py-1 px-2 +} + +.p-datatable.p-datatable-sm .p-datatable-tfoot > tr > td { + @apply py-1 px-2 +} + +.p-datatable.p-datatable-sm .p-datatable-footer { + @apply py-1 px-2 +} + +.p-datatable.p-datatable-lg .p-datatable-header { + @apply py-4 px-5 +} + +.p-datatable.p-datatable-lg .p-datatable-thead > tr > th { + @apply py-4 px-5 +} + +.p-datatable.p-datatable-lg .p-datatable-tbody>tr>td { + @apply py-4 px-5 +} + +.p-datatable.p-datatable-lg .p-datatable-tfoot>tr>td { + @apply py-4 px-5 +} + +.p-datatable.p-datatable-lg .p-datatable-footer { + @apply py-4 px-5 +} + +.p-datatable-row-toggle-button { + @apply inline-flex items-center justify-center overflow-hidden relative w-7 h-7 cursor-pointer select-none + transition-colors duration-200 rounded-full border-none bg-transparent + text-surface-500 enabled:hover:bg-surface-100 enabled:hover:text-surface-700 + dark:text-surface-400 dark:enabled:hover:bg-surface-800 dark:enabled:hover:text-surface-0 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary + +} + +.p-datatable-tbody > tr.p-datatable-row-selected .p-datatable-row-toggle-button:hover { + @apply bg-surface-0 dark:bg-surface-900 text-primary +} + +.p-datatable-row-toggle-icon:dir(rtl) { + @apply rotate-180 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/dataview.css b/frontend/packages/kwai-ui/src/css/primevue/dataview.css new file mode 100644 index 000000000..12f5b0750 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/dataview.css @@ -0,0 +1,29 @@ +@import './paginator'; + +.p-dataview { + @apply border-none +} + +.p-dataview-header { + @apply py-3 px-4 border-b border-surface-200 dark:border-surface-700 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 +} + +.p-dataview-content { + @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 +} + +.p-dataview-footer { + @apply py-3 px-4 border-t border-surface-200 dark:border-surface-700 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 +} + +.p-dataview-paginator-top { + @apply border-b border-surface-200 dark:border-surface-700 +} + +.p-dataview-paginator-bottom { + @apply border-t border-surface-200 dark:border-surface-700 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/datepicker.css b/frontend/packages/kwai-ui/src/css/primevue/datepicker.css new file mode 100644 index 000000000..122759842 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/datepicker.css @@ -0,0 +1,211 @@ +@import './button'; +@import './inputtext'; + +.p-datepicker { + @apply inline-flex max-w-full +} + +.p-datepicker-input { + @apply flex-auto w-[1%] +} + +.p-datepicker:has(.p-datepicker-dropdown) .p-datepicker-input { + @apply rounded-e-none +} + +.p-datepicker-dropdown { + @apply inline-flex items-center justify-center overflow-hidden relative cursor-pointer select-none + w-10 rounded-e-md border border-s-0 border-surface-300 dark:border-surface-700 + bg-surface-100 enabled:hover:bg-surface-200 enabled:active:bg-surface-300 + text-surface-600 enabled:hover:text-surface-700 enabled:active:text-surface-800 + dark:bg-surface-800 dark:enabled:hover:bg-surface-700 dark:enabled:active:bg-surface-600 + dark:text-surface-300 dark:enabled:hover:text-surface-200 dark:enabled:active:text-surface-100 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary + transition-colors duration-200 +} + +.p-datepicker:has(.p-datepicker-input-icon-container) { + @apply relative +} + +.p-datepicker:has(.p-datepicker-input-icon-container) .p-datepicker-input { + @apply pe-10 +} + +.p-datepicker-input-icon-container { + @apply cursor-pointer absolute top-1/2 end-3 -mt-2 text-surface-400 +} + +.p-datepicker-fluid { + @apply flex +} + +.p-datepicker-fluid .p-datepicker-input { + @apply w-[1%] +} + +.p-datepicker .p-datepicker-panel { + @apply min-w-full +} + +.p-datepicker-panel { + @apply w-auto p-3 rounded-md + border border-surface-200 dark:border-surface-700 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-datepicker-panel-inline { + @apply inline-block overflow-x-auto shadow-none +} + +.p-datepicker-header { + @apply flex items-center justify-between pt-0 px-0 pb-2 font-medium gap-2 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + border-b border-surface-200 dark:border-surface-700 +} + +.p-datepicker-next-button:dir(rtl) { + @apply order-[-1] +} +.p-datepicker-prev-button:dir(rtl) { + @apply order-1 +} + +.p-datepicker-title { + @apply flex items-center justify-between gap-2 font-medium +} + +.p-datepicker-select-year, +.p-datepicker-select-month { + @apply border-none bg-transparent m-0 cursor-pointer font-medium transition-colors duration-200 + py-1 px-2 rounded-md text-surface-700 dark:text-surface-0 + enabled:hover:bg-surface-100 enabled:hover:text-surface-800 + dark:enabled:hover:bg-surface-800 dark:enabled:hover:text-surface-0 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-datepicker-calendar-container { + @apply flex +} + +.p-datepicker-calendar-container .p-datepicker-calendar { + @apply flex-auto border-s border-surface-200 dark:border-surface-700 gap-3 + first:ps-0 first:border-s-0 last:pe-0 +} + +.p-datepicker-day-view { + @apply w-full border-collapse text-base mt-2 mx-0 mb-0 +} + +.p-datepicker-weekday-cell { + @apply p-1 +} + +.p-datepicker-weekday { + @apply font-medium text-surface-700 dark:text-surface-0 +} + +.p-datepicker-day-cell { + @apply p-1 +} + +.p-datepicker-day { + @apply flex items-center justify-center cursor-pointer my-0 mx-auto overflow-hidden relative w-8 h-8 + rounded-full p-1 transition-colors duration-200 border border-transparent text-surface-700 dark:text-surface-0 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-datepicker-day:not(.p-datepicker-day-selected):not(.p-disabled):hover { + @apply bg-surface-100 text-surface-800 dark:bg-surface-800 dark:text-surface-0 +} + +.p-datepicker-day-selected { + @apply bg-primary text-primary-contrast +} + +.p-datepicker-day-selected-range { + @apply bg-highlight +} + +.p-datepicker-today > .p-datepicker-day { + @apply bg-surface-200 text-surface-900 dark:bg-surface-700 dark:text-surface-0 +} + +.p-datepicker-today > .p-datepicker-day-selected { + @apply bg-primary text-primary-contrast +} + +.p-datepicker-today > .p-datepicker-day-selected-range { + @apply bg-highlight +} + +.p-datepicker-weeknumber { + @apply text-center +} + +.p-datepicker-month-view { + @apply mt-2 mb-0 mx-0 +} + +.p-datepicker-month { + @apply w-1/3 inline-flex items-center justify-center cursor-pointer overflow-hidden relative + p-[0.375rem] transition-colors duration-200 rounded-md text-surface-700 dark:text-surface-0 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-datepicker-month:not(.p-disabled):not(.p-datepicker-month-selected):hover { + @apply bg-surface-100 text-surface-800 dark:bg-surface-800 dark:text-surface-0 +} + +.p-datepicker-month-selected { + @apply bg-primary text-primary-contrast +} + +.p-datepicker-year-view { + @apply mt-2 mb-0 mx-0 +} + +.p-datepicker-year { + @apply w-1/2 inline-flex items-center justify-center cursor-pointer overflow-hidden relative + p-[0.375rem] transition-colors duration-200 rounded-md text-surface-700 dark:text-surface-0 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-datepicker-year:not(.p-disabled):not(.p-datepicker-year-selected):hover { + @apply bg-surface-100 text-surface-800 dark:bg-surface-800 dark:text-surface-0 +} + +.p-datepicker-year-selected { + @apply bg-primary text-primary-contrast +} + +.p-datepicker-buttonbar { + @apply flex justify-between items-center pt-2 pb-0 px-0 border-t border-surface-200 dark:border-surface-700 +} + +.p-datepicker-buttonbar .p-button { + @apply w-auto +} + +.p-datepicker-time-picker { + @apply flex items-center justify-center border-t border-surface-200 dark:border-surface-700 p-0 gap-2 +} + +.p-datepicker-calendar-container + .p-datepicker-time-picker { + @apply pt-2 pb-0 px-0 +} + +.p-datepicker-time-picker > div { + @apply flex items-center flex-col gap-1 +} + +.p-datepicker-time-picker span { + @apply text-base +} + +.p-datepicker-timeonly .p-datepicker-time-picker { + @apply border-t-0 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/dialog.css b/frontend/packages/kwai-ui/src/css/primevue/dialog.css new file mode 100644 index 000000000..8c9ddf89f --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/dialog.css @@ -0,0 +1,125 @@ +@import './button'; + +.p-dialog { + @apply max-h-[90%] scale-100 rounded-xl + border border-surface-200 dark:border-surface-700 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + shadow-[0_20px_25px_-5px_rgba(0,0,0,0.1),0_8px_10px_-6px_rgba(0,0,0,0.1)] +} + +.p-dialog-content { + @apply overflow-y-auto pt-0 px-5 pb-5 +} + +.p-dialog-header { + @apply flex items-center justify-between shrink-0 p-5 +} + +.p-dialog-title { + @apply font-semibold text-xl +} + +.p-dialog-footer { + @apply shrink-0 pt-0 px-5 pb-5 flex justify-end gap-2 +} + +.p-dialog-header-actions { + @apply flex items-center gap-2 +} + +.p-dialog-enter-active { + @apply transition-all duration-150 ease-[cubic-bezier(0,0,0.2,1)] +} + +.p-dialog-leave-active { + @apply transition-all duration-150 ease-[cubic-bezier(0.4,0,0.2,1)] +} + +.p-dialog-enter-from, +.p-dialog-leave-to { + @apply opacity-0 scale-75 +} + +.p-dialog-top .p-dialog, +.p-dialog-bottom .p-dialog, +.p-dialog-left .p-dialog, +.p-dialog-right .p-dialog, +.p-dialog-topleft .p-dialog, +.p-dialog-topright .p-dialog, +.p-dialog-bottomleft .p-dialog, +.p-dialog-bottomright .p-dialog { + @apply m-3 [transform:translate3d(0,0,0)] +} + +.p-dialog-top .p-dialog-enter-active, +.p-dialog-top .p-dialog-leave-active, +.p-dialog-bottom .p-dialog-enter-active, +.p-dialog-bottom .p-dialog-leave-active, +.p-dialog-left .p-dialog-enter-active, +.p-dialog-left .p-dialog-leave-active, +.p-dialog-right .p-dialog-enter-active, +.p-dialog-right .p-dialog-leave-active, +.p-dialog-topleft .p-dialog-enter-active, +.p-dialog-topleft .p-dialog-leave-active, +.p-dialog-topright .p-dialog-enter-active, +.p-dialog-topright .p-dialog-leave-active, +.p-dialog-bottomleft .p-dialog-enter-active, +.p-dialog-bottomleft .p-dialog-leave-active, +.p-dialog-bottomright .p-dialog-enter-active, +.p-dialog-bottomright .p-dialog-leave-active { + @apply transition-all duration-300 ease-out +} + +.p-dialog-top .p-dialog-enter-from, +.p-dialog-top .p-dialog-leave-to { + @apply [transform:translate3d(0,-100%,0)] +} + +.p-dialog-bottom .p-dialog-enter-from, +.p-dialog-bottom .p-dialog-leave-to { + @apply [transform:translate3d(0,100%,0)] +} + +.p-dialog-left .p-dialog-enter-from, +.p-dialog-left .p-dialog-leave-to, +.p-dialog-topleft .p-dialog-enter-from, +.p-dialog-topleft .p-dialog-leave-to, +.p-dialog-bottomleft .p-dialog-enter-from, +.p-dialog-bottomleft .p-dialog-leave-to { + @apply [transform:translate3d(-100%,0,0)] +} + +.p-dialog-right .p-dialog-enter-from, +.p-dialog-right .p-dialog-leave-to, +.p-dialog-topright .p-dialog-enter-from, +.p-dialog-topright .p-dialog-leave-to, +.p-dialog-bottomright .p-dialog-enter-from, +.p-dialog-bottomright .p-dialog-leave-to { + @apply [transform:translate3d(100%,0,0)] +} + +.p-dialog-left:dir(rtl) .p-dialog-enter-from, +.p-dialog-left:dir(rtl) .p-dialog-leave-to, +.p-dialog-topleft:dir(rtl) .p-dialog-enter-from, +.p-dialog-topleft:dir(rtl) .p-dialog-leave-to, +.p-dialog-bottomleft:dir(rtl) .p-dialog-enter-from, +.p-dialog-bottomleft:dir(rtl) .p-dialog-leave-to { + @apply [transform:translate3d(100%,0,0)] +} +.p-dialog-right:dir(rtl) .p-dialog-enter-from, +.p-dialog-right:dir(rtl) .p-dialog-leave-to, +.p-dialog-topright:dir(rtl) .p-dialog-enter-from, +.p-dialog-topright:dir(rtl) .p-dialog-leave-to, +.p-dialog-bottomright:dir(rtl) .p-dialog-enter-from, +.p-dialog-bottomright:dir(rtl) .p-dialog-leave-to { + @apply [transform:translate3d(-100%,0,0)] +} + +.p-dialog-maximized { + @apply !w-screen !h-screen top-0 start-0 max-h-full rounded-none +} + +.p-dialog-maximized .p-dialog-content { + @apply flex-grow +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/divider.css b/frontend/packages/kwai-ui/src/css/primevue/divider.css new file mode 100644 index 000000000..1bb448bb0 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/divider.css @@ -0,0 +1,52 @@ +.p-divider-horizontal { + @apply flex w-full relative items-center my-4 mx-0 py-0 px-4 + before:absolute before:block before:top-1/2 before:start-0 before:w-full + before:border-t before:border-surface-200 dark:before:border-surface-700 +} + +.p-divider-horizontal .p-divider-content { + @apply py-0 px-2 +} + +.p-divider-vertical { + @apply min-h-full flex relative justify-center my-0 mx-4 py-2 px-0 + before:absolute before:block before:top-0 before:start-1/2 before:h-full + before:border-s before:border-surface-200 before:dark:border-surface-700 +} + +.p-divider.p-divider-vertical .p-divider-content { + @apply py-2 px-0 +} + +.p-divider-content { + @apply z-10 bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 +} + +.p-divider-solid.p-divider-horizontal:before { + @apply border-solid +} + +.p-divider-solid.p-divider-vertical:before { + @apply border-solid +} + +.p-divider-dashed.p-divider-horizontal:before { + @apply border-dashed +} + +.p-divider-dashed.p-divider-vertical:before { + @apply border-dashed +} + +.p-divider-dotted.p-divider-horizontal:before { + @apply border-dotted +} + +.p-divider-dotted.p-divider-vertical:before { + @apply border-dotted +} + +.p-divider-left:dir(rtl), +.p-divider-right:dir(rtl) { + @apply flex-row-reverse +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/dock.css b/frontend/packages/kwai-ui/src/css/primevue/dock.css new file mode 100644 index 000000000..54d5f9cfc --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/dock.css @@ -0,0 +1,84 @@ +.p-dock { + @apply absolute z-10 flex justify-center items-center pointer-events-none +} + +.p-dock-list-container { + @apply flex pointer-events-auto bg-white/10 border border-white/10 p-2 rounded-xl +} + +.p-dock-list { + @apply m-0 p-0 list-none flex items-center justify-center outline-none +} + +.p-dock-item { + @apply transition-all duration-200 ease-[cubic-bezier(0.4,0,0.2,1)] will-change-transform p-2 rounded-md + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-dock-item-link { + @apply flex flex-col items-center justify-center relative cursor-default w-12 h-12 +} + +.p-dock-top { + @apply start-0 top-0 w-full +} + +.p-dock-top .p-dock-item { + @apply origin-[center_top] +} + +.p-dock-bottom { + @apply start-0 bottom-0 w-full +} + +.p-dock-bottom .p-dock-item { + @apply origin-[center_bottom] +} + +.p-dock-right { + @apply end-0 top-0 h-full +} + +.p-dock-right .p-dock-item { + @apply origin-[center_right] +} + +.p-dock-right .p-dock-list { + @apply flex-col +} + +.p-dock-left { + @apply start-0 top-0 h-full +} + +.p-dock-left .p-dock-item { + @apply origin-[center_left] +} + +.p-dock-left .p-dock-list { + @apply flex-col +} + +.p-dock-mobile.p-dock-top .p-dock-list-container, +.p-dock-mobile.p-dock-bottom .p-dock-list-container { + @apply overflow-x-auto w-full +} + +.p-dock-mobile.p-dock-top .p-dock-list-container .p-dock-list, +.p-dock-mobile.p-dock-bottom .p-dock-list-container .p-dock-list { + @apply mt-0 mx-auto +} + +.p-dock-mobile.p-dock-left .p-dock-list-container, +.p-dock-mobile.p-dock-right .p-dock-list-container { + @apply overflow-y-auto h-full +} + +.p-dock-mobile.p-dock-left .p-dock-list-container .p-dock-list, +.p-dock-mobile.p-dock-right .p-dock-list-container .p-dock-list { + @apply mt-auto mx-0 +} + +.p-dock-mobile .p-dock-list .p-dock-item { + @apply transform-none m-0 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/drawer.css b/frontend/packages/kwai-ui/src/css/primevue/drawer.css new file mode 100644 index 000000000..fe5aa85cd --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/drawer.css @@ -0,0 +1,94 @@ +@import './button'; + +.p-drawer { + @apply flex flex-col pointer-events-auto relative transition-transform duration-300 + border border-surface-200 dark:border-surface-700 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + shadow-[0_20px_25px_-5px_rgba(0,0,0,0.1),0_8px_10px_-6px_rgba(0,0,0,0.1)] +} + +.p-drawer { + @apply [transform:translate3d(0,0,0)] +} + +.p-drawer-content { + @apply overflow-y-auto flex-grow pt-0 pb-5 px-5 +} + +.p-drawer-header { + @apply flex items-center justify-between flex-shrink-0 p-5 +} + +.p-drawer-footer { + @apply px-5 +} + +.p-drawer-title { + @apply font-semibold text-2xl +} + +.p-drawer-full .p-drawer { + @apply transition-none transform-none w-screen h-screen max-h-full top-0 left-0 +} + +.p-drawer-left .p-drawer-enter-from, +.p-drawer-left .p-drawer-leave-to { + @apply -translate-x-full +} + +.p-drawer-right .p-drawer-enter-from, +.p-drawer-right .p-drawer-leave-to { + @apply translate-x-full +} + +.p-drawer-top .p-drawer-enter-from, +.p-drawer-top .p-drawer-leave-to { + @apply -translate-y-full +} + +.p-drawer-bottom .p-drawer-enter-from, +.p-drawer-bottom .p-drawer-leave-to { + @apply translate-y-full +} + +.p-drawer-full .p-drawer-enter-from, +.p-drawer-full .p-drawer-leave-to { + @apply opacity-0 +} + +.p-drawer-full .p-drawer-enter-active, +.p-drawer-full .p-drawer-leave-active { + @apply transition-opacity animate-duration-400 ease-[cubic-bezier(0.25,0.8,0.25,1)] +} + +.p-drawer-left .p-drawer { + @apply w-80 h-full border-r +} + +.p-drawer-right .p-drawer { + @apply w-80 h-full border-s +} + +.p-drawer-top .p-drawer { + @apply h-40 w-full border-b +} + +.p-drawer-bottom .p-drawer { + @apply h-40 w-full border-t +} + +.p-drawer-left .p-drawer-content, +.p-drawer-right .p-drawer-content, +.p-drawer-top .p-drawer-content, +.p-drawer-bottom .p-drawer-content { + @apply w-full h-full +} + +.p-drawer-open { + @apply flex +} + +.p-overlay-mask:dir(rtl) { + @apply flex-row-reverse; +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/fieldset.css b/frontend/packages/kwai-ui/src/css/primevue/fieldset.css new file mode 100644 index 000000000..28c2bddda --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/fieldset.css @@ -0,0 +1,45 @@ +.p-fieldset { + @apply border border-surface-200 dark:border-surface-700 rounded-md + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + px-[1.125rem] pt-0 pb-[1.125rem] +} + +.p-fieldset-legend { + @apply border border-transparent rounded-md px-3 py-2 + transition-colors duration-200 +} + +.p-fieldset-toggleable > .p-fieldset-legend { + @apply p-0 +} + +.p-fieldset-toggle-button { + @apply select-none overflow-hidden relative + flex items-center justify-center gap-2 + px-3 py-2 + border-none rounded-md + bg-surface-0 dark:bg-surface-900 + hover:bg-surface-100 dark:hover:bg-surface-800 + text-surface-700 dark:text-surface-0 + hover:text-surface-800 dark:hover:text-surface-0 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary + transition-colors duration-200 +} + +.p-fieldset-legend-label { + @apply font-semibold; +} + +.p-fieldset-toggle-icon { + @apply text-surface-500 dark:text-surface-400 + transition-colors duration-200 +} + +.p-fieldset-toggle-button:hover .p-fieldset-toggle-icon { + @apply text-surface-600 dark:text-surface-300 +} + +.p-fieldset .p-fieldset-content { + @apply p-0 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/fileupload.css b/frontend/packages/kwai-ui/src/css/primevue/fileupload.css new file mode 100644 index 000000000..74ce46d9a --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/fileupload.css @@ -0,0 +1,57 @@ +@import './button'; +@import './message'; +@import './progressbar'; + +.p-fileupload input[type="file"] { + @apply hidden +} + +.p-fileupload-advanced { + @apply border border-surface-200 dark:border-surface-700 rounded-md + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 +} + +.p-fileupload-header { + @apply flex items-center p-[1.125rem] gap-2 text-surface-700 dark:text-surface-0 +} + +.p-fileupload-content { + @apply border border-transparent relative transition-colors duration-200 pt-0 px-[1.125rem] pb-[1.125rem] +} + +.p-fileupload-content .p-progressbar { + @apply w-full absolute top-0 start-0 h-1 +} + +.p-fileupload-file-list { + @apply flex flex-col gap-2 mt-[1.125rem] +} + +.p-fileupload-file { + @apply flex flex-wrap items-center p-4 border-b border-surface-200 dark:border-surface-700 gap-2 last:border-b-0 +} + +.p-fileupload-file-info { + @apply flex flex-col gap-2 +} + +.p-fileupload-file-thumbnail { + @apply flex-shrink-0 +} + +.p-fileupload-file-actions { + @apply ms-auto +} + +.p-fileupload-highlight { + @apply border border-dashed border-primary +} + +.p-fileupload-advanced .p-message { + @apply mt-0 +} + +.p-fileupload-basic { + @apply flex flex-wrap items-center justify-center gap-2 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/floatlabel.css b/frontend/packages/kwai-ui/src/css/primevue/floatlabel.css new file mode 100644 index 000000000..f2544ee7c --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/floatlabel.css @@ -0,0 +1,73 @@ +.p-floatlabel { + @apply block relative +} + +.p-floatlabel label { + @apply absolute pointer-events-none top-1/2 -translate-y-1/2 transition-all duration-200 ease-out leading-none font-medium + start-3 text-surface-500 dark:text-surface-400 +} + +.p-floatlabel:has(.p-textarea) label { + @apply top-2 translate-y-0 +} + +.p-floatlabel:has(.p-inputicon:first-child) label { + @apply start-10 +} + +.p-floatlabel:has(.p-invalid) label { + @apply text-red-400 dark:text-red-300 +} + +.p-floatlabel:has(input:focus) label, +.p-floatlabel:has(input.p-filled) label, +.p-floatlabel:has(input:-webkit-autofill) label, +.p-floatlabel:has(textarea:focus) label, +.p-floatlabel:has(textarea.p-filled) label, +.p-floatlabel:has(.p-inputwrapper-focus) label, +.p-floatlabel:has(.p-inputwrapper-filled) label { + @apply -top-5 translate-y-0 text-xs font-normal +} + +.p-floatlabel:has(input.p-filled) label, +.p-floatlabel:has(textarea.p-filled) label, +.p-floatlabel:has(.p-inputwrapper-filled) label { + @apply text-surface-500 dark:text-surface-400 +} + +.p-floatlabel:has(input:focus) label, +.p-floatlabel:has(input:-webkit-autofill) label, +.p-floatlabel:has(textarea:focus) label , +.p-floatlabel:has(.p-inputwrapper-focus) label { + @apply text-primary +} + +.p-floatlabel-in .p-inputtext, +.p-floatlabel-in .p-textarea, +.p-floatlabel-in .p-select-label, +.p-floatlabel-in .p-multiselect-label, +.p-floatlabel-in .p-autocomplete-input-multiple, +.p-floatlabel-in .p-cascadeselect-label, +.p-floatlabel-in .p-treeselect-label { + @apply pt-6 pb-2 +} + +.p-floatlabel-in:has(input:focus) label, +.p-floatlabel-in:has(input.p-filled) label, +.p-floatlabel-in:has(input:-webkit-autofill) label, +.p-floatlabel-in:has(textarea:focus) label, +.p-floatlabel-in:has(textarea.p-filled) label, +.p-floatlabel-in:has(.p-inputwrapper-focus) label, +.p-floatlabel-in:has(.p-inputwrapper-filled) label { + @apply top-2 +} + +.p-floatlabel-on:has(input:focus) label, +.p-floatlabel-on:has(input.p-filled) label, +.p-floatlabel-on:has(input:-webkit-autofill) label, +.p-floatlabel-on:has(textarea:focus) label, +.p-floatlabel-on:has(textarea.p-filled) label, +.p-floatlabel-on:has(.p-inputwrapper-focus) label, +.p-floatlabel-on:has(.p-inputwrapper-filled) label { + @apply top-0 -translate-y-1/2 rounded-sm bg-surface-0 dark:bg-surface-950 py-0 px-[0.125rem] +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/galleria.css b/frontend/packages/kwai-ui/src/css/primevue/galleria.css new file mode 100644 index 000000000..e4edff962 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/galleria.css @@ -0,0 +1,244 @@ +.p-galleria { + @apply overflow-hidden border border-surface-200 dark:border-surface-700 rounded-md +} + +.p-galleria-content { + @apply flex flex-col +} + +.p-galleria-items-container { + @apply flex flex-col relative +} + +.p-galleria-items { + @apply relative flex h-full +} + +.p-galleria-nav-button { + @apply absolute top-1/2 inline-flex justify-center items-center overflow-hidden select-none border-none cursor-pointer + w-12 h-12 transition-colors duration-200 p-0 -mt-12 mx-2 mb-0 rounded-full + bg-white/10 text-surface-100 enabled:hover:bg-white/20 enabled:hover:text-surface-0 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-galleria-next-icon, +.p-galleria-prev-icon { + @apply text-2xl w-6 h-6 +} + +.p-galleria-prev-button { + @apply start-0 +} + +.p-galleria-next-button { + @apply end-0 +} + +.p-galleria-prev-button:dir(rtl) { + @apply start-auto end-0 +} +.p-galleria-next-button:dir(rtl) { + @apply end-auto start-0 +} + +.p-galleria-item { + @apply flex justify-center items-center h-full w-full +} + +.p-galleria-hover-navigators .p-galleria-nav-button { + @apply pointer-events-none opacity-0 transition-opacity duration-200 ease-in-out +} + +.p-galleria-hover-navigators .p-galleria-items-container:hover .p-galleria-nav-button { + @apply pointer-events-auto opacity-100 +} + +.p-galleria-hover-navigators .p-galleria-items-container:hover .p-galleria-nav-button.p-disabled { + @apply pointer-events-none +} + +.p-galleria-caption { + @apply absolute bottom-0 left-0 w-full bg-black/5 text-surface-100 p-4 +} + +.p-galleria-thumbnails { + @apply flex flex-col overflow-auto flex-shrink-0 +} + +.p-galleria-thumbnail-nav-button { + @apply self-center flex-grow-0 flex-shrink-0 basis-auto justify-center items-center overflow-hidden relative + my-0 mx-2 p-0 border-none select-none cursor-pointer w-8 h-8 rounded-md transition-colors duration-200 bg-transparent + text-surface-600 hover:bg-surface-100 hover:text-surface-700 + dark:text-surface-400 dark:hover:bg-surface-800 dark:hover:text-surface-0 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-galleria-thumbnail-nav-button .p-galleria-thumbnail-next-icon, +.p-galleria-thumbnail-nav-button .p-galleria-thumbnail-prev-icon { + @apply text-base w-4 h-4 +} + +.p-galleria-thumbnails-content { + @apply flex flex-row bg-surface-0 dark:bg-surface-900 py-4 px-1 +} + +.p-galleria-thumbnails-viewport { + @apply overflow-hidden w-full +} + +.p-galleria:not(.p-galleria-thumbnails-right):not(.p-galleria-thumbnails-left) .p-galleria-thumbnail-prev-button:dir(rtl), +.p-galleria:not(.p-galleria-thumbnails-right):not(.p-galleria-thumbnails-left) .p-galleria-thumbnail-next-button:dir(rtl) { + @apply rotate-180 +} + +.p-galleria-thumbnail-items { + @apply flex +} + +.p-galleria-thumbnail-item { + @apply overflow-auto flex items-center justify-center cursor-pointer opacity-50 +} + +.p-galleria-thumbnail { + @apply outline-transparent transition-opacity duration-300 hover:opacity-100 +} + +.p-galleria-thumbnail-item-current { + @apply opacity-100 +} + +.p-galleria-thumbnails-left .p-galleria-content, +.p-galleria-thumbnails-right .p-galleria-content { + @apply flex-row +} + +.p-galleria-thumbnails-left .p-galleria-items-container, +.p-galleria-thumbnails-right .p-galleria-items-container { + @apply flex-row +} + +.p-galleria-thumbnails-left .p-galleria-items-container, +.p-galleria-thumbnails-top .p-galleria-items-container { + @apply order-2 +} + +.p-galleria-thumbnails-left .p-galleria-thumbnails, +.p-galleria-thumbnails-top .p-galleria-thumbnails { + @apply order-1 +} + +.p-galleria-thumbnails-left .p-galleria-thumbnails-content, +.p-galleria-thumbnails-right .p-galleria-thumbnails-content { + @apply flex-col flex-grow +} + +.p-galleria-thumbnails-left .p-galleria-thumbnail-items, +.p-galleria-thumbnails-right .p-galleria-thumbnail-items { + @apply flex-col h-full +} + +.p-galleria-indicator-list { + @apply flex items-center justify-center p-4 gap-2 m-0 list-none +} + +.p-galleria-indicator-button { + @apply inline-flex items-center w-4 h-4 rounded-full m-0 p-0 border-none select-none cursor-pointer transition-colors duration-200 + bg-surface-200 hover:bg-surface-300 dark:bg-surface-700 dark:hover:bg-surface-600 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-galleria-indicator-active .p-galleria-indicator-button { + @apply bg-primary +} + +.p-galleria-indicators-left .p-galleria-items-container, +.p-galleria-indicators-right .p-galleria-items-container { + @apply flex-row items-center +} + +.p-galleria-indicators-left .p-galleria-items, +.p-galleria-indicators-top .p-galleria-items { + @apply order-2 +} + +.p-galleria-indicators-left .p-galleria-indicator-list, +.p-galleria-indicators-top .p-galleria-indicator-list { + @apply order-1 +} + +.p-galleria-indicators-left .p-galleria-indicator-list, +.p-galleria-indicators-right .p-galleria-indicator-list { + @apply flex-col +} + +.p-galleria-inset-indicators .p-galleria-indicator-list { + @apply absolute flex z-10 bg-black/50 +} + +.p-galleria-inset-indicators .p-galleria-indicator-button { + @apply bg-white/40 hover:bg-white/60 +} + +.p-galleria-inset-indicators .p-galleria-indicator-active .p-galleria-indicator-button { + @apply bg-white/90 +} + +.p-galleria-inset-indicators.p-galleria-indicators-top .p-galleria-indicator-list { + @apply top-0 left-0 w-full items-start +} + +.p-galleria-inset-indicators.p-galleria-indicators-right .p-galleria-indicator-list { + @apply right-0 top-0 h-full items-end +} + +.p-galleria-inset-indicators.p-galleria-indicators-bottom .p-galleria-indicator-list { + @apply bottom-0 left-0 w-full items-end +} + +.p-galleria-inset-indicators.p-galleria-indicators-left .p-galleria-indicator-list { + @apply left-0 top-0 h-full items-start +} + +.p-galleria-mask { + @apply fixed top-0 left-0 w-full h-full flex items-center justify-center +} + +.p-galleria-close-button { + @apply absolute top-0 right-0 flex items-center justify-center overflow-hidden m-2 rounded-full + transition-colors duration-200 select-none cursor-pointer w-12 h-12 p-0 border-none + bg-white/10 text-surface-50 hover:bg-white/20 hover:text-surface-0 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-galleria-close-icon { + @apply text-2xl w-6 h-6 +} + +.p-galleria-mask .p-galleria-nav-button { + @apply fixed top-1/2 +} + +.p-galleria-enter-active { + @apply transition-all duration-150 ease-[cubic-bezier(0,0,0.2,1)] +} + +.p-galleria-leave-active { + @apply transition-all duration-150 ease-[cubic-bezier(0.4,0,0.2,1)] +} + +.p-galleria-enter-from, +.p-galleria-leave-to { + @apply opacity-0 scale-75 +} + +.p-galleria-enter-active .p-galleria-nav-button { + @apply opacity-0 +} + +.p-items-hidden .p-galleria-thumbnail-item { + @apply invisible +} + +.p-items-hidden .p-galleria-thumbnail-item.p-galleria-thumbnail-item-active { + @apply visible +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/iconfield.css b/frontend/packages/kwai-ui/src/css/primevue/iconfield.css new file mode 100644 index 000000000..d7aaf1118 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/iconfield.css @@ -0,0 +1,23 @@ +.p-iconfield { + @apply relative +} + +.p-inputicon { + @apply absolute top-1/2 -mt-2 text-surface-400 leading-none +} + +.p-iconfield .p-inputicon:first-child { + @apply start-3 +} + +.p-iconfield .p-inputicon:last-child { + @apply end-3 +} + +.p-iconfield .p-inputtext:not(:first-child) { + @apply ps-10 +} + +.p-iconfield .p-inputtext:not(:last-child) { + @apply pe-10 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/iftalabel.css b/frontend/packages/kwai-ui/src/css/primevue/iftalabel.css new file mode 100644 index 000000000..dc323f922 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/iftalabel.css @@ -0,0 +1,32 @@ +.p-iftalabel { + @apply block relative +} + +.p-iftalabel label { + @apply absolute pointer-events-none top-2 transition-all ease-out duration-200 leading-none text-xs font-medium start-3 text-surface-500 dark:text-surface-400 +} + +.p-iftalabel .p-inputtext, +.p-iftalabel .p-textarea, +.p-iftalabel .p-select-label, +.p-iftalabel .p-multiselect-label, +.p-iftalabel .p-autocomplete-input-multiple, +.p-iftalabel .p-cascadeselect-label, +.p-iftalabel .p-treeselect-label { + @apply pt-6 pb-2 +} + +.p-iftalabel:has(.p-invalid) label { + @apply text-red-400 dark:text-red-300 +} + +.p-iftalabel:has(input:focus) label , +.p-iftalabel:has(input:-webkit-autofill) label, +.p-iftalabel:has(textarea:focus) label , +.p-iftalabel:has(.p-inputwrapper-focus) label { + @apply text-primary +} + +.p-iftalabel .p-inputicon { + @apply top-6 translate-y-1/4 mt-0 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/image.css b/frontend/packages/kwai-ui/src/css/primevue/image.css new file mode 100644 index 000000000..7cb3e4616 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/image.css @@ -0,0 +1,56 @@ +.p-image-mask { + @apply flex items-center justify-center +} + +.p-image-preview { + @apply relative inline-flex leading-none +} + +.p-image-preview-mask { + @apply absolute start-0 top-0 w-full h-full flex items-center justify-center opacity-0 + border-none p-0 cursor-pointer bg-transparent text-surface-200 transition-all duration-200 +} + +.p-image-preview:hover > .p-image-preview-mask { + @apply opacity-100 cursor-pointer bg-black/40 dark:bg-black/60 +} + +.p-image-preview-icon { + @apply text-2xl w-6 h-6 +} + +.p-image-toolbar { + @apply absolute top-4 end-4 start-auto bottom-auto flex z-10 p-2 bg-white/10 border border-white/20 rounded-3xl gap-2; +} + +.p-image-action { + @apply inline-flex justify-center items-center text-surface-50 bg-transparent w-12 h-12 m-0 p-0 + border-none cursor-pointer select-none rounded-full transition-colors duration-200 + hover:text-surface-0 hover:bg-white/10 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-image-action .p-icon { + @apply text-2xl h-6 w-6 +} + +.p-image-action.p-disabled { + @apply pointer-events-auto +} + +.p-image-original { + @apply transition-transform duration-150 max-w-[100vw] max-h-[100vh] +} + +.p-image-original-enter-active { + @apply transition-all duration-150 ease-[cubic-bezier(0,0,0.2,1)] +} + +.p-image-original-leave-active { + @apply transition-all duration-150 ease-[cubic-bezier(0.4,0,0.2,1)] +} + +.p-image-original-enter-from, +.p-image-original-leave-to { + @apply opacity-0 scale-75 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/imagecompare.css b/frontend/packages/kwai-ui/src/css/primevue/imagecompare.css new file mode 100644 index 000000000..64151b4dc --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/imagecompare.css @@ -0,0 +1,38 @@ +.p-imagecompare { + @apply relative overflow-hidden w-full aspect-video +} + +.p-imagecompare img { + @apply w-full h-full absolute +} + +.p-imagecompare img + img { + @apply [clip-path:polygon(0_0,50%_0,50%_100%,0_100%)] +} + +.p-imagecompare:dir(rtl) img + img { + @apply [clip-path:polygon(50%_0,100%_0,100%_100%,50%_100%)] +} + +.p-imagecompare-slider { + @apply relative appearance-none w-[calc(100%+1rem)] h-full -ms-2 bg-transparent outline-none transition-all duration-200 + hover:w-[calc(100%+2rem)] hover:-ms-4 +} + +.p-imagecompare-slider::-webkit-slider-thumb { + @apply appearance-none h-4 w-4 bg-white/30 rounded-full bg-contain cursor-ew-resize transition-all duration-200 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-imagecompare-slider::-moz-range-thumb { + @apply appearance-none h-4 w-4 bg-white/30 rounded-full bg-contain cursor-ew-resize transition-all duration-200 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-imagecompare-slider:hover::-webkit-slider-thumb { + @apply bg-white/40 h-8 w-8 +} + +.p-imagecompare-slider:hover::-moz-range-thumb { + @apply bg-white/40 h-8 w-8 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/inplace.css b/frontend/packages/kwai-ui/src/css/primevue/inplace.css new file mode 100644 index 000000000..cefc826d7 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/inplace.css @@ -0,0 +1,13 @@ +.p-inplace-display { + @apply inline cursor-pointer border border-transparent px-3 py-2 rounded-md + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary + transition-colors duration-200 +} + +.p-inplace-display:not(.p-disabled):hover { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-inplace-content { + @apply block +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/inputgroup.css b/frontend/packages/kwai-ui/src/css/primevue/inputgroup.css new file mode 100644 index 000000000..99db68584 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/inputgroup.css @@ -0,0 +1,67 @@ +.p-inputgroup, +.p-inputgroup .p-floatlabel, +.p-inputgroup .p-iftalabel { + @apply flex items-stretch w-full +} + +.p-inputgroup .p-inputtext, +.p-inputgroup .p-inputwrapper { + @apply flex-auto w-[1%] +} + +.p-inputgroupaddon { + @apply flex items-center justify-center p-2 min-w-10 + border-y border-surface-300 dark:border-surface-700 + bg-surface-0 dark:bg-surface-950 text-surface-400 +} + +.p-inputgroupaddon:first-child, +.p-inputgroupaddon + .p-inputgroupaddon { + @apply border-s +} + +.p-inputgroupaddon:last-child { + @apply border-e +} + +.p-inputgroup > .p-component, +.p-inputgroup > .p-inputwrapper > .p-component, +.p-inputgroup > .p-floatlabel > .p-component, +.p-inputgroup > .p-floatlabel > .p-inputwrapper > .p-component, +.p-inputgroup > .p-iftalabel > .p-component, +.p-inputgroup > .p-iftalabel > .p-inputwrapper > .p-component { + @apply rounded-none m-0 +} + +.p-inputgroupaddon:first-child, +.p-inputgroup > .p-component:first-child, +.p-inputgroup > .p-inputwrapper:first-child > .p-component, +.p-inputgroup > .p-floatlabel:first-child > .p-component, +.p-inputgroup > .p-floatlabel:first-child > .p-inputwrapper > .p-component, +.p-inputgroup > .p-iftalabel:first-child > .p-component, +.p-inputgroup > .p-iftalabel:first-child > .p-inputwrapper > .p-component { + @apply rounded-s-md +} + +.p-inputgroupaddon:last-child, +.p-inputgroup > .p-component:last-child, +.p-inputgroup > .p-inputwrapper:last-child > .p-component, +.p-inputgroup > .p-floatlabel:last-child > .p-component, +.p-inputgroup > .p-floatlabel:last-child > .p-inputwrapper > .p-component, +.p-inputgroup > .p-iftalabel:last-child > .p-component, +.p-inputgroup > .p-iftalabel:last-child > .p-inputwrapper > .p-component { + @apply rounded-e-md +} + +.p-inputgroup .p-component:focus, +.p-inputgroup .p-component.p-focus, +.p-inputgroup .p-inputwrapper-focus, +.p-inputgroup .p-component:focus ~ label, +.p-inputgroup .p-component.p-focus ~ label, +.p-inputgroup .p-inputwrapper-focus ~ label { + @apply z-10 +} + +.p-inputgroup > .p-button:not(.p-button-icon-only) { + @apply w-auto +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/inputnumber.css b/frontend/packages/kwai-ui/src/css/primevue/inputnumber.css new file mode 100644 index 000000000..bdef17232 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/inputnumber.css @@ -0,0 +1,84 @@ +@import './inputtext'; + +.p-inputnumber { + @apply inline-flex relative +} + +.p-inputnumber-button { + @apply flex items-center justify-center flex-grow-0 flex-shrink-0 basis-auto cursor-pointer w-10 + bg-transparent enabled:hover:bg-surface-100 enabled:active:bg-surface-200 + border border-surface-300 enabled:hover:border-surface-300 enabled:active:border-surface-300 + text-surface-400 enabled:hover:text-surface-500 enabled:active:text-surface-600 + dark:bg-transparent dark:enabled:hover:bg-surface-800 dark:enabled:active:bg-surface-700 + dark:border-surface-700 dark:enabled:hover:border-surface-700 dark:enabled:active:border-surface-700 + dark:text-surface-400 dark:enabled:hover:text-surface-300 dark:enabled:active:text-surface-200 + transition-colors duration-200 +} + +.p-inputnumber-stacked .p-inputnumber-button { + @apply relative flex-auto border-none +} + +.p-inputnumber-stacked .p-inputnumber-button-group { + @apply flex flex-col absolute top-px end-px h-[calc(100%-2px)] z-10 +} + +.p-inputnumber-stacked .p-inputnumber-increment-button { + @apply p-0 rounded-tr-[5px] +} + +.p-inputnumber-stacked .p-inputnumber-decrement-button { + @apply p-0 rounded-br-[5px] +} + +.p-inputnumber-horizontal .p-inputnumber-increment-button { + @apply order-3 rounded-e-md border-s-0 +} + +.p-inputnumber-horizontal .p-inputnumber-input { + @apply order-2 rounded-none +} + +.p-inputnumber-horizontal .p-inputnumber-decrement-button { + @apply order-1 rounded-s-md border-r-0 +} + +.p-floatlabel:has(.p-inputnumber-horizontal) label { + @apply ms-10 +} + +.p-inputnumber-vertical { + @apply flex-col +} + +.p-inputnumber-vertical .p-inputnumber-button { + @apply py-2 +} + +.p-inputnumber-vertical .p-inputnumber-increment-button { + @apply order-1 rounded-ss-md rounded-se-md w-full border-b-0 +} + +.p-inputnumber-vertical .p-inputnumber-input { + @apply order-2 rounded-none text-center +} + +.p-inputnumber-vertical .p-inputnumber-decrement-button { + @apply order-3 rounded-ee-md rounded-es-md w-full border-t-0 +} + +.p-inputnumber-input { + @apply flex-auto +} + +.p-inputnumber-fluid { + @apply w-full +} + +.p-inputnumber-fluid .p-inputnumber-input { + @apply w-[1%] +} + +.p-inputnumber-fluid.p-inputnumber-vertical .p-inputnumber-input { + @apply w-full +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/inputotp.css b/frontend/packages/kwai-ui/src/css/primevue/inputotp.css new file mode 100644 index 000000000..d727efbae --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/inputotp.css @@ -0,0 +1,9 @@ +@import './inputtext'; + +.p-inputotp { + @apply flex items-center gap-2 +} + +.p-inputotp-input { + @apply text-center w-10 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/inputtext.css b/frontend/packages/kwai-ui/src/css/primevue/inputtext.css new file mode 100644 index 000000000..c03d3744c --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/inputtext.css @@ -0,0 +1,34 @@ +.p-inputtext { + @apply appearance-none rounded-md + border border-surface-300 dark:border-surface-700 + enabled:hover:border-surface-400 dark:enabled:hover:border-surface-600 + enabled:focus:border-primary + bg-surface-0 dark:bg-surface-950 + text-surface-700 dark:text-surface-0 + disabled:bg-surface-200 disabled:text-surface-500 dark:disabled:bg-surface-700 dark:disabled:text-surface-400 disabled:opacity-100 + placeholder:text-surface-500 dark:placeholder:text-surface-400 + px-3 py-2 + transition-colors duration-200 + shadow-[0_1px_2px_0_rgba(18,18,23,0.05)] + outline-none +} + +.p-inputtext.p-invalid { + @apply border-red-400 dark:border-red-300 +} + +.p-inputtext.p-variant-filled { + @apply bg-surface-50 dark:bg-surface-800 +} + +.p-inputtext-sm { + @apply text-sm px-[0.625rem] py-[0.375rem] +} + +.p-inputtext-lg { + @apply text-lg px-[0.875rem] py-[0.625rem] +} + +.p-inputtext-fluid { + @apply w-full +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/knob.css b/frontend/packages/kwai-ui/src/css/primevue/knob.css new file mode 100644 index 000000000..276761aab --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/knob.css @@ -0,0 +1,37 @@ +.p-knob-range { + @apply fill-none transition-[stroke] duration-100 ease-in +} + +.p-knob-text { + @apply text-xl text-center +} + +.p-knob svg { + @apply rounded-full + transition-colors duration-200 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-knob svg path:first-child { + @apply stroke-surface-200 dark:stroke-surface-700 +} + +.p-knob svg path + path { + @apply stroke-primary +} + +.p-knob svg text { + @apply fill-surface-500 dark:fill-surface-400 +} + +.p-knob-value { + animation-name: p-knob-dash-frame; + animation-fill-mode: forwards; + fill: none; +} + +@keyframes p-knob-dash-frame { + 100% { + stroke-dashoffset: 0; + } +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/listbox.css b/frontend/packages/kwai-ui/src/css/primevue/listbox.css new file mode 100644 index 000000000..ded48775a --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/listbox.css @@ -0,0 +1,79 @@ +@import './inputtext'; +@import './iconfield'; + +.p-listbox { + @apply bg-surface-0 dark:bg-surface-950 text-surface-700 dark:text-surface-0 + border border-surface-300 dark:border-surface-700 rounded-md + shadow-[0_1px_2px_0_rgba(18,18,23,0.05)] + transition-colors duration-200 +} + +.p-listbox.p-focus { + @apply border-primary +} + +.p-listbox.p-disabled { + @apply bg-surface-200 text-surface-500 dark:bg-surface-700 dark:text-surface-400 opacity-100 cursor-default +} + +.p-listbox.p-disabled .p-listbox-option { + @apply text-surface-500 dark:text-surface-400 cursor-default +} + +.p-listbox.p-invalid { + @apply border-red-400 dark:border-red-300 +} + +.p-listbox-header { + @apply pt-2 pb-1 px-4 +} + +.p-listbox-filter { + @apply w-full +} + +.p-listbox-list-container { + @apply overflow-auto +} + +.p-listbox-list { + @apply list-none m-0 p-1 outline-none flex flex-col gap-[2px] +} + +.p-listbox-option { + @apply flex items-center cursor-pointer relative overflow-hidden px-3 py-2 border-none rounded-sm + text-surface-700 dark:text-surface-0 + transition-colors duration-200 +} + +.p-listbox-striped li:nth-child(even of .p-listbox-option) { + @apply bg-surface-50 dark:bg-surface-900 +} + +.p-listbox .p-listbox-list .p-listbox-option.p-listbox-option-selected { + @apply bg-highlight +} + +.p-listbox:not(.p-disabled) .p-listbox-option.p-listbox-option-selected.p-focus { + @apply bg-highlight-emphasis +} + +.p-listbox:not(.p-disabled) .p-listbox-option:not(.p-listbox-option-selected):not(.p-disabled).p-focus { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-listbox:not(.p-disabled) .p-listbox-option:not(.p-listbox-option-selected):not(.p-disabled):hover { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-listbox-option-check-icon { + @apply relative -ms-[0.375rem] me-[0.375rem] text-surface-700 dark:text-surface-0 +} + +.p-listbox-option-group { + @apply m-0 px-3 py-2 text-surface-500 dark:text-surface-400 font-semibold +} + +.p-listbox-empty-message { + @apply px-3 py-2 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/megamenu.css b/frontend/packages/kwai-ui/src/css/primevue/megamenu.css new file mode 100644 index 000000000..08a232bce --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/megamenu.css @@ -0,0 +1,207 @@ +.p-megamenu { + @apply relative flex items-center rounded-md gap-2 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + border border-surface-200 dark:border-surface-700 +} + +.p-megamenu-start, +.p-megamenu-end { + @apply flex items-center +} + +.p-megamenu-root-list { + @apply m-0 p-0 list-none outline-none flex items-center flex-wrap gap-2 +} + +.p-megamenu-root-list > .p-megamenu-item > .p-menumegamenubar-item-content { + @apply rounded-md +} + +.p-megamenu-root-list > .p-megamenu-item > .p-megamenu-item-content > .p-megamenu-item-link { + @apply px-3 py-2 +} + +.p-megamenu-item-content { + @apply transition-colors duration-200 rounded-sm text-surface-700 dark:text-surface-0 +} + +.p-megamenu-item-link { + @apply cursor-pointer flex items-center no-underline overflow-hidden relative text-inherit + px-3 py-2 gap-2 select-none outline-none +} + +.p-megamenu-item-icon { + @apply text-surface-400 dark:text-surface-500 +} + +.p-megamenu-submenu-icon { + @apply text-surface-400 dark:text-surface-500 ms-auto text-sm w-[0.875rem] h-[0.875rem] +} + +.p-megamenu-item.p-focus > .p-megamenu-item-content { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-megamenu-item.p-focus > .p-megamenu-item-content .p-megamenu-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-megamenu-item.p-focus > .p-megamenu-item-content .p-megamenu-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-megamenu-item:not(.p-disabled) > .p-megamenu-item-content:hover { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-megamenu-item:not(.p-disabled) > .p-megamenu-item-content:hover .p-megamenu-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-megamenu-item:not(.p-disabled) > .p-megamenu-item-content:hover .p-megamenu-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-megamenu-item-active > .p-megamenu-item-content { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-megamenu-item-active > .p-megamenu-item-content .p-megamenu-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-megamenu-item-active > .p-megamenu-item-content .p-megamenu-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-megamenu-overlay { + @apply hidden absolute w-auto z-10 start-0 min-w-full rounded-md + bg-surface-0 dark:bg-surface-900 + border border-surface-200 dark:border-surface-700 + text-surface-700 dark:text-surface-0 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-megamenu-root-list > .p-megamenu-item-active > .p-megamenu-overlay { + @apply block +} + +.p-megamenu-submenu { + @apply m-0 p-1 list-none min-w-52 flex flex-col gap-[2px] +} + +.p-megamenu-submenu-label { + @apply px-3 py-2 text-surface-500 dark:text-surface-400 font-semibold bg-transparent +} + +.p-megamenu-separator { + @apply border-t border-surface-200 dark:border-surface-700 +} + +.p-megamenu-horizontal { + @apply items-center px-3 py-2 +} + +.p-megamenu-horizontal .p-megamenu-root-list { + @apply flex items-center flex-wrap gap-2 +} + +.p-megamenu-horizontal .p-megamenu-end { + @apply ms-auto self-center +} + +.p-megamenu-vertical { + @apply inline-flex min-w-52 flex-col items-stretch p-1 +} + +.p-megamenu-vertical .p-megamenu-root-list { + @apply items-stretch flex-col gap-[2px] +} + +.p-megamenu-vertical .p-megamenu-root-list > .p-megamenu-item-active > .p-megamenu-overlay { + @apply start-full top-0 +} + +.p-megamenu-vertical .p-megamenu-root-list > .p-megamenu-item > .p-megamenu-item-content .p-megamenu-submenu-icon { + @apply ms-auto +} + +.p-megamenu-grid { + @apply flex +} + +.p-megamenu-col-2, +.p-megamenu-col-3, +.p-megamenu-col-4, +.p-megamenu-col-6, +.p-megamenu-col-12 { + @apply flex-grow-0 flex-shrink-0 basis-auto p-2 +} + +.p-megamenu-col-2 { + @apply w-1/6; +} + +.p-megamenu-col-3 { + @apply w-1/4 +} + +.p-megamenu-col-4 { + @apply w-1/3 +} + +.p-megamenu-col-6 { + @apply w-1/2 +} + +.p-megamenu-col-12 { + @apply w-full +} + +.p-megamenu-button { + @apply hidden justify-center items-center cursor-pointer w-7 h-7 relative border-none rounded-full + text-surface-500 dark:text-surface-400 hover:text-surface-600 dark:hover:text-surface-300 + bg-transparent hover:bg-surface-100 dark:hover:bg-surface-800 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary + transition-colors duration-200 +} + +.p-megamenu-mobile { + @apply flex +} + +.p-megamenu-mobile .p-megamenu-button { + @apply flex +} + +.p-megamenu-mobile .p-megamenu-root-list { + @apply absolute hidden flex-col top-full start-0 z-10 w-full p-1 gap-[2px] + bg-surface-0 dark:bg-surface-900 + border border-surface-200 dark:border-surface-700 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-megamenu-mobile-active .p-megamenu-root-list { + @apply flex +} + +.p-megamenu-mobile .p-megamenu-root-list .p-megamenu-item { + @apply w-full static +} + +.p-megamenu-mobile .p-megamenu-overlay { + @apply static border-none rounded-none shadow-none +} + +.p-megamenu-mobile .p-megamenu-grid { + @apply flex-wrap overflow-auto max-h-[90%] +} + +.p-megamenu-mobile .p-megamenu-root-list > .p-megamenu-item > .p-megamenu-item-content .p-megamenu-submenu-icon { + @apply ms-auto transition-transform duration-[200ms] +} + +.p-megamenu-mobile .p-megamenu-root-list > .p-megamenu-item-active > .p-megamenu-item-content .p-megamenu-submenu-icon { + @apply -rotate-180 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/menu.css b/frontend/packages/kwai-ui/src/css/primevue/menu.css new file mode 100644 index 000000000..d5e095aa0 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/menu.css @@ -0,0 +1,51 @@ +.p-menu { + @apply bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + border border-surface-200 dark:border-surface-700 + rounded-md min-w-52 +} + +.p-menu-list { + @apply m-0 p-1 list-none outline-none flex flex-col gap-[2px] +} + +.p-menu-item-content { + @apply transition-colors duration-200 rounded-sm text-surface-700 dark:text-surface-0 +} + +.p-menu-item-link { + @apply cursor-pointer flex items-center no-underline overflow-hidden relative text-inherit + px-3 py-2 gap-2 select-none outline-none +} + +.p-menu-item-icon { + @apply text-surface-400 dark:text-surface-500 +} + +.p-menu-item.p-focus .p-menu-item-content { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-menu-item.p-focus .p-menu-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-menu-item:not(.p-disabled) .p-menu-item-content:hover { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-menu-item:not(.p-disabled) .p-menu-item-content:hover .p-menu-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-menu-overlay { + @apply shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-menu-submenu-label { + @apply bg-transparent px-3 py-2 text-surface-500 dark:text-surface-400 font-semibold +} + +.p-menu-separator { + @apply border-t border-surface-200 dark:border-surface-700 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/menubar.css b/frontend/packages/kwai-ui/src/css/primevue/menubar.css new file mode 100644 index 000000000..c989af621 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/menubar.css @@ -0,0 +1,169 @@ +.p-menubar { + @apply flex items-center rounded-md px-3 py-2 gap-2 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + border border-surface-200 dark:border-surface-700 +} + +.p-menubar-start, +.p-megamenu-end { + @apply flex items-center +} + +.p-menubar-root-list, +.p-menubar-submenu { + @apply flex m-0 p-0 list-none outline-none +} + +.p-menubar-root-list { + @apply items-center flex-wrap gap-2 +} + +.p-menubar-root-list > .p-menubar-item > .p-menubar-item-content { + @apply rounded-md +} + +.p-menubar-root-list > .p-menubar-item > .p-menubar-item-content > .p-menubar-item-link { + @apply px-3 py-2 +} + +.p-menubar-item-content { + @apply transition-colors duration-200 rounded-sm text-surface-700 dark:text-surface-0 +} + +.p-menubar-item-link { + @apply cursor-pointer flex items-center no-underline overflow-hidden relative text-inherit + px-3 py-2 gap-2 select-none outline-none +} + +.p-menubar-item-icon { + @apply text-surface-400 dark:text-surface-500 +} + +.p-menubar-submenu-icon { + @apply text-surface-400 dark:text-surface-500 ms-auto text-sm w-[0.875rem] h-[0.875rem] +} + +.p-menubar-submenu-icon:dir(rtl) { + @apply rotate-180 +} + +.p-menubar-item.p-focus > .p-menubar-item-content { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-menubar-item.p-focus > .p-menubar-item-content .p-menubar-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-menubar-item.p-focus > .p-menubar-item-content .p-menubar-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-menubar-item:not(.p-disabled) > .p-menubar-item-content:hover { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-menubar-item:not(.p-disabled) > .p-menubar-item-content:hover .p-menubar-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-menubar-item:not(.p-disabled) > .p-menubar-item-content:hover .p-menubar-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-menubar-item-active > .p-menubar-item-content { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-menubar-item-active > .p-menubar-item-content .p-menubar-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-menubar-item-active > .p-menubar-item-content .p-menubar-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-menubar-submenu { + @apply hidden absolute min-w-52 z-10 + bg-surface-0 dark:bg-surface-900 + border border-surface-200 dark:border-surface-700 + text-surface-700 dark:text-surface-0 + flex-col p-1 gap-[2px] rounded-md + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-menubar-submenu .p-menubar-separator { + @apply border-t border-surface-200 dark:border-surface-700 +} + +.p-menubar-submenu .p-menubar-item { + @apply relative +} + + .p-menubar-submenu > .p-menubar-item-active > .p-menubar-submenu { + @apply block start-full top-0 +} + +.p-menubar-end { + @apply ms-auto self-center +} + +.p-menubar-button { + @apply hidden justify-center items-center cursor-pointer w-7 h-7 relative border-none rounded-full + text-surface-500 dark:text-surface-400 hover:text-surface-600 dark:hover:text-surface-300 + bg-transparent hover:bg-surface-100 dark:hover:bg-surface-800 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary + transition-colors duration-200 +} + +.p-menubar-mobile { + @apply relative +} + +.p-menubar-mobile .p-menubar-button { + @apply flex +} + +.p-menubar-mobile .p-menubar-root-list { + @apply absolute hidden w-full flex-col top-full start-0 z-10 p-1 gap-[2px] rounded-md + border border-surface-200 dark:border-surface-700 + bg-surface-0 dark:bg-surface-900 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-menubar-mobile .p-menubar-root-list > .p-menubar-item > .p-menubar-item-content > .p-menubar-item-link { + @apply px-3 py-3 +} + +.p-menubar-mobile-active .p-menubar-root-list { + @apply flex +} + +.p-menubar-mobile .p-menubar-root-list .p-menubar-item { + @apply w-full static +} + +.p-menubar-mobile .p-menubar-root-list .p-menubar-separator { + @apply border-t border-surface-200 dark:border-surface-700 +} + +.p-menubar-mobile .p-menubar-root-list > .p-menubar-item > .p-menubar-item-content .p-menubar-submenu-icon { + @apply ms-auto transition-transform duration-[200ms] +} + +.p-menubar-mobile .p-menubar-root-list > .p-menubar-item-active > .p-menubar-item-content .p-menubar-submenu-icon { + @apply -rotate-180 +} + +.p-menubar-mobile .p-menubar-submenu .p-menubar-submenu-icon { + @apply transition-transform duration-200 rotate-90 +} + +.p-menubar-mobile .p-menubar-item-active > .p-menubar-item-content .p-menubar-submenu-icon { + @apply -rotate-90 +} + +.p-menubar-mobile .p-menubar-submenu { + @apply w-full static shadow-none border-none ps-4 pe-0 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/message.css b/frontend/packages/kwai-ui/src/css/primevue/message.css new file mode 100644 index 000000000..7ba971140 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/message.css @@ -0,0 +1,212 @@ +.p-message { + @apply rounded-md outline outline-1 +} + +.p-message-content { + @apply flex items-center px-3 py-2 gap-2 h-full +} + +.p-message-icon { + @apply flex-shrink-0 +} + +.p-message-close-button { + @apply flex items-center justify-center flex-shrink-0 ms-auto overflow-hidden relative cursor-pointer select-none + w-7 h-7 rounded-full bg-transparent transition-colors duration-200 text-inherit p-0 border-none + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 +} + +.p-message-info { + @apply bg-blue-50/95 outline-blue-200 text-blue-600 + dark:bg-blue-500/15 dark:outline-blue-700/35 dark:text-blue-500 + shadow-[0px_4px_8px_0px_theme(colors.blue.500/0.04)] +} + +.p-message-info .p-message-close-button { + @apply hover:bg-blue-100 focus-visible:outline-blue-600 + dark:hover:bg-white/5 dark:focus-visible:outline-blue-500 +} + +.p-message-info.p-message-outlined { + @apply text-blue-500 outline-blue-500 dark:text-blue-600 dark:outline-blue-600 +} + +.p-message-info.p-message-simple { + @apply text-blue-500 dark:text-blue-600 +} + +.p-message-success { + @apply bg-green-50/95 outline-green-200 text-green-600 + dark:bg-green-500/15 dark:outline-green-700/35 dark:text-green-500 + shadow-[0px_4px_8px_0px_theme(colors.green.500/0.04)] +} + +.p-message-success .p-message-close-button { + @apply hover:bg-green-100 focus-visible:outline-green-600 + dark:hover:bg-white/5 dark:focus-visible:outline-green-500 +} + +.p-message-success.p-message-outlined { + @apply text-green-500 outline-green-500 dark:text-green-600 dark:outline-green-600 +} + +.p-message-success.p-message-simple { + @apply text-green-500 dark:text-green-600 +} + +.p-message-warn { + @apply bg-yellow-50/95 outline-yellow-200 text-yellow-600 + dark:bg-yellow-500/15 dark:outline-yellow-700/35 dark:text-yellow-500 + shadow-[0px_4px_8px_0px_theme(colors.yellow.500/0.04)] +} + +.p-message-warn .p-message-close-button { + @apply hover:bg-yellow-100 focus-visible:outline-yellow-600 + dark:hover:bg-white/5 dark:focus-visible:outline-yellow-500 +} + +.p-message-warn.p-message-outlined { + @apply text-yellow-500 outline-yellow-500 dark:text-yellow-600 dark:outline-yellow-600 +} + +.p-message-warn.p-message-simple { + @apply text-yellow-500 dark:text-yellow-600 +} + +.p-message-error { + @apply bg-red-50/95 outline-red-200 text-red-600 + dark:bg-red-500/15 dark:outline-red-700/35 dark:text-red-500 + shadow-[0px_4px_8px_0px_theme(colors.red.500/0.04)] +} + +.p-message-error .p-message-close-button { + @apply hover:bg-red-100 focus-visible:outline-red-600 + dark:hover:bg-white/5 dark:focus-visible:outline-red-500 +} + +.p-message-error.p-message-outlined { + @apply text-red-500 outline-red-500 dark:text-red-600 dark:outline-red-600 +} + +.p-message-error.p-message-simple { + @apply text-red-500 dark:text-red-600 +} + +.p-message-secondary { + @apply bg-surface-100 outline-surface-200 text-surface-600 + dark:bg-surface-800 dark:outline-surface-700 dark:text-surface-300 + shadow-[0px_4px_8px_0px_rgba(0,0,0,0.04)] +} + +.p-message-secondary .p-message-close-button { + @apply hover:bg-surface-200 focus-visible:outline-surface-600 + dark:hover:bg-surface-700 dark:focus-visible:outline-surface-300 +} + +.p-message-secondary.p-message-outlined { + @apply text-surface-500 outline-surface-500 dark:text-surface-600 dark:outline-surface-600 +} + +.p-message-secondary.p-message-simple { + @apply text-surface-500 dark:text-surface-600 +} + +.p-message-contrast { + @apply bg-surface-900 outline-surface-950 text-surface-50 + dark:bg-surface-0 dark:outline-surface-100 dark:text-surface-950 + shadow-[0px_4px_8px_0px_rgba(0,0,0,0.04)] +} + +.p-message-contrast .p-message-close-button { + @apply hover:bg-surface-800 focus-visible:outline-surface-50 + dark:hover:bg-surface-100 dark:focus-visible:outline-surface-950 +} + +.p-message-contrast.p-message-outlined { + @apply text-surface-950 outline-surface-950 dark:text-surface-0 dark:outline-surface-0 +} + +.p-message-contrast.p-message-simple { + @apply text-surface-950 dark:text-surface-0 +} + +.p-message-text { + @apply text-base font-medium +} + +.p-message-icon { + @apply text-lg w-[1.125rem] h-[1.125rem] +} + +.p-message-enter-from { + @apply opacity-0 +} + +.p-message-enter-active { + @apply transition-opacity duration-300 +} + +.p-message.p-message-leave-from { + @apply max-h-[1000px] +} + +.p-message.p-message-leave-to { + @apply max-h-0 opacity-0 m-0 +} + +.p-message-leave-active { + @apply overflow-hidden [transition:max-height_0.45s_cubic-bezier(0,1,0,1),opacity_0.3s,margin0.3s] +} + +.p-message-leave-active .p-message-close-button { + @apply opacity-0 +} + +.p-message-sm .p-message-content { + @apply px-2.5 py-[0.375rem] +} + +.p-message-sm .p-message-text { + @apply text-sm +} + +.p-message-sm .p-message-icon { + @apply w-4 h-4 text-sm +} + +.p-message-sm .p-message-close-icon { + @apply w-3.5 h-3.5 text-sm +} + +.p-message-lg .p-message-content { + @apply px-3.5 py-2.5 +} + +.p-message-lg .p-message-text { + @apply text-xl +} + +.p-message-lg .p-message-icon { + @apply w-5 h-5 text-xl +} + +.p-message-lg .p-message-close-icon { + @apply w-[1.125rem] h-[1.125rem] text-xl +} + +.p-message-outlined { + @apply bg-transparent outline outline-1 +} + +.p-message-simple { + @apply bg-transparent outline-none shadow-none +} + +.p-message-simple .p-message-content { + @apply p-0 +} + +.p-message-outlined .p-message-close-button:hover, +.p-message-simple .p-message-close-button:hover { + @apply bg-transparent +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/metergroup.css b/frontend/packages/kwai-ui/src/css/primevue/metergroup.css new file mode 100644 index 000000000..74227a115 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/metergroup.css @@ -0,0 +1,67 @@ +.p-metergroup { + @apply flex gap-4 +} + +.p-metergroup-meters { + @apply flex bg-surface-200 dark:bg-surface-700 rounded-md +} + +.p-metergroup-label-list { + @apply flex flex-wrap m-0 p-0 list-none +} + +.p-metergroup-label { + @apply inline-flex items-center gap-2 +} + +.p-metergroup-label-marker { + @apply inline-flex w-2 h-2 rounded-full +} + +.p-metergroup-label-icon { + @apply text-base w-4 h-4 +} + +.p-metergroup-horizontal { + @apply flex-col +} + +.p-metergroup-label-list-horizontal { + @apply gap-4 +} + +.p-metergroup-horizontal .p-metergroup-meters { + @apply h-2 +} + +.p-metergroup-horizontal .p-metergroup-meter:first-of-type { + @apply rounded-s-md +} + +.p-metergroup-horizontal .p-metergroup-meter:last-of-type { + @apply rounded-e-md +} + +.p-metergroup-vertical { + @apply flex-row +} + +.p-metergroup-label-list-vertical { + @apply flex-col gap-2 +} + +.p-metergroup-vertical .p-metergroup-meters { + @apply flex-col w-2 h-full +} + +.p-metergroup-vertical .p-metergroup-label-list { + @apply items-start +} + +.p-metergroup-vertical .p-metergroup-meter:first-of-type { + @apply rounded-ss-md rounded-se-md +} + +.p-metergroup-vertical .p-metergroup-meter:last-of-type { + @apply rounded-ee-md rounded-es-md +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/multiselect.css b/frontend/packages/kwai-ui/src/css/primevue/multiselect.css new file mode 100644 index 000000000..a6d7e59c8 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/multiselect.css @@ -0,0 +1,139 @@ +@import './checkbox'; +@import './chip'; +@import './inputtext'; +@import './iconfield'; + +.p-multiselect { + @apply inline-flex cursor-pointer relative select-none rounded-md + bg-surface-0 dark:bg-surface-950 + border border-surface-300 dark:border-surface-700 + shadow-[0_1px_2px_0_rgba(18,18,23,0.05)] + transition-colors duration-200 +} + +.p-multiselect:not(.p-disabled):hover { + @apply border-surface-400 dark:border-surface-600 +} + +.p-multiselect:not(.p-disabled).p-focus { + @apply border-primary +} + +.p-multiselect.p-variant-filled { + @apply bg-surface-50 dark:bg-surface-800 +} + +.p-multiselect.p-invalid { + @apply border-red-400 dark:border-red-300 +} + +.p-multiselect.p-disabled { + @apply bg-surface-200 text-surface-500 dark:bg-surface-700 dark:text-surface-400 opacity-100 cursor-default +} + +.p-multiselect-dropdown { + @apply flex items-center justify-center shrink-0 bg-transparent + text-surface-500 dark:text-surface-400 w-10 rounded-e-md +} + +.p-multiselect-label-container { + @apply overflow-hidden flex-auto +} + +.p-multiselect-label { + @apply flex items-center gap-1 whitespace-nowrap overflow-hidden text-ellipsis px-3 py-2 text-surface-700 dark:text-surface-0 +} + +.p-multiselect-label.p-placeholder { + @apply text-surface-500 dark:text-surface-400 +} + +.p-multiselect.p-disabled .p-multiselect-label { + @apply text-surface-500 dark:text-surface-400 +} + +.p-multiselect-label-empty { + @apply overflow-hidden opacity-0 +} + +.p-multiselect .p-multiselect-overlay { + @apply min-w-full +} + +.p-multiselect-overlay { + @apply absolute top-0 left-0 rounded-md + bg-surface-0 dark:bg-surface-900 + border border-surface-200 dark:border-surface-700 + text-surface-700 dark:text-surface-0 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-multiselect-header { + @apply flex items-center pt-2 pb-1 px-4 +} + +.p-multiselect-header .p-checkbox { + @apply me-2 +} + +.p-multiselect-filter-container { + @apply flex-auto +} + +.p-multiselect-filter { + @apply w-full +} + +.p-multiselect-list-container { + @apply overflow-auto +} + +.p-multiselect-list { + @apply m-0 p-1 list-none gap-[2px] flex flex-col +} + +.p-multiselect-option { + @apply cursor-pointer font-normal whitespace-nowrap relative overflow-hidden flex items-center gap-2 px-3 py-2 + rounded-sm text-surface-700 dark:text-surface-0 bg-transparent border-none + transition-colors duration-200 +} + +.p-multiselect-option:not(.p-disabled).p-focus { + @apply bg-surface-100 dark:bg-surface-800 text-surface-600 dark:text-surface-0 +} + +.p-multiselect-option-group { + @apply m-0 px-3 py-2 bg-transparent text-surface-500 dark:text-surface-400 font-semibold +} + +.p-multiselect-empty-message { + @apply px-3 py-2 +} + +.p-multiselect-label .p-chip { + @apply py-1 rounded-sm +} + +.p-multiselect-label:has(.p-chip) { + @apply py-1 px-[0.375rem] +} + +.p-multiselect-fluid { + @apply flex +} + +.p-multiselect-sm .p-multiselect-label { + @apply text-sm px-[0.625rem] py-[0.375rem] +} + +.p-multiselect-sm .p-multiselect-dropdown .p-icon { + @apply text-sm w-[0.875rem] h-[0.875rem] +} + +.p-multiselect-lg .p-multiselect-label { + @apply text-lg px-[0.875rem] py-[0.625rem] +} + +.p-multiselect-lg .p-multiselect-dropdown .p-icon { + @apply text-lg w-[1.125rem] h-[1.125rem] +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/orderlist.css b/frontend/packages/kwai-ui/src/css/primevue/orderlist.css new file mode 100644 index 000000000..99619f931 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/orderlist.css @@ -0,0 +1,10 @@ +@import './button'; +@import './listbox'; + +.p-orderlist { + @apply flex gap-[1.125rem] +} + +.p-orderlist-controls { + @apply flex flex-col justify-center gap-2 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/organizationchart.css b/frontend/packages/kwai-ui/src/css/primevue/organizationchart.css new file mode 100644 index 000000000..69bbb496a --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/organizationchart.css @@ -0,0 +1,71 @@ +.p-organizationchart-table { + @apply border-spacing-0 border-separate my-0 mx-auto +} + +.p-organizationchart-table > tbody > tr > td { + @apply text-center align-top py-0 px-3 +} + +.p-organizationchart-node { + @apply inline-block relative py-3 px-4 rounded-md + border border-surface-200 dark:border-surface-700 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + transition-colors duration-200 +} + +.p-organizationchart-node:has(.p-organizationchart-node-toggle-button) { + @apply pt-3 px-4 pb-5 +} + +.p-organizationchart-node.p-organizationchart-node-selectable:not(.p-organizationchart-node-selected):hover { + @apply bg-surface-100 text-surface-800 dark:bg-surface-800 dark:text-surface-0 +} + +.p-organizationchart-node-selected { + @apply bg-highlight +} + +.p-organizationchart-node-toggle-button { + @apply absolute -bottom-3 -ms-3 z-20 start-1/2 select-none cursor-pointer w-6 h-6 no-underline rounded-full + inline-flex items-center justify-center transition-colors duration-200 + border border-surface-200 dark:border-surface-700 + bg-surface-0 text-surface-500 hover:bg-surface-100 hover:text-surface-700 + dark:bg-surface-900 dark:text-surface-400 dark:hover:bg-surface-800 dark:hover:text-surface-0 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} +.p-organizationchart-node-toggle-button-icon { + @apply relative top-px +} + +.p-organizationchart-connector-down { + @apply my-0 mx-auto h-6 w-px bg-surface-200 dark:bg-surface-700 +} + +.p-organizationchart-connector-right { + @apply rounded-none +} + +.p-organizationchart-connector-left { + @apply rounded-none border-e border-surface-200 dark:border-surface-700 +} + +.p-organizationchart-connector-top { + @apply border-t border-surface-200 dark:border-surface-700 +} + +.p-organizationchart-node-selectable { + @apply cursor-pointer +} + +.p-organizationchart-connectors :nth-child(1 of .p-organizationchart-connector-left) { + @apply border-e-0 +} + +.p-organizationchart-connectors :nth-last-child(1 of .p-organizationchart-connector-left) { + @apply rounded-se-md +} + +.p-organizationchart-connectors :nth-child(1 of .p-organizationchart-connector-right) { + @apply border-s border-surface-200 dark:border-surface-700 rounded-ss-md +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/overlaybadge.css b/frontend/packages/kwai-ui/src/css/primevue/overlaybadge.css new file mode 100644 index 000000000..c0193ea23 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/overlaybadge.css @@ -0,0 +1,13 @@ +@import './badge'; + +.p-overlaybadge { + @apply relative +} + +.p-overlaybadge .p-badge { + @apply absolute top-0 end-0 translate-x-[50%] translate-y-[-50%] origin-[100%_0] m-0 outline outline-2 outline-surface-0 dark:outline-surface-900 +} + +.p-overlaybadge .p-badge:dir(rtl) { + @apply -translate-x-1/2 -translate-y-1/2 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/paginator.css b/frontend/packages/kwai-ui/src/css/primevue/paginator.css new file mode 100644 index 000000000..25d694302 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/paginator.css @@ -0,0 +1,58 @@ +.p-paginator { + @apply flex items-center justify-center flex-wrap py-2 px-4 rounded-md gap-1 + bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 +} + +.p-paginator-content { + @apply flex items-center justify-center flex-wrap gap-1 +} + +.p-paginator-content-start { + @apply ms-auto +} + +.p-paginator-content-end { + @apply me-auto +} + +.p-paginator-page, +.p-paginator-next, +.p-paginator-last, +.p-paginator-first, +.p-paginator-prev { + @apply cursor-pointer inline-flex items-center justify-center leading-none overflow-hidden relative + bg-transparent border-none min-w-10 h-10 transition-colors duration-200 rounded-full p-0 m-0 + text-surface-500 dark:text-surface-400 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-paginator-page:not(.p-disabled):not(.p-paginator-page-selected):hover, +.p-paginator-first:not(.p-disabled):hover, +.p-paginator-prev:not(.p-disabled):hover, +.p-paginator-next:not(.p-disabled):hover, +.p-paginator-last:not(.p-disabled):hover { + @apply bg-surface-100 text-surface-600 dark:bg-surface-800 dark:text-surface-300 +} + +.p-paginator-page.p-paginator-page-selected { + @apply bg-highlight +} + +.p-paginator-current { + @apply text-surface-500 dark:text-surface-400 +} + +.p-paginator-pages { + @apply flex items-center gap-1 +} + +.p-paginator-jtp-input .p-inputtext { + @apply max-w-10 +} + +.p-paginator-first:dir(rtl), +.p-paginator-prev:dir(rtl), +.p-paginator-next:dir(rtl), +.p-paginator-last:dir(rtl) { + @apply rotate-180 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/panel.css b/frontend/packages/kwai-ui/src/css/primevue/panel.css new file mode 100644 index 000000000..6a9aa44a6 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/panel.css @@ -0,0 +1,27 @@ +@import './button'; + +.p-panel { + @apply border border-surface-200 dark:border-surface-700 rounded-md + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 +} + +.p-panel-header { + @apply flex justify-between items-center p-[1.125rem] +} + +.p-panel-toggleable .p-panel-header { + @apply py-[0.375rem] px-[1.125rem] +} + +.p-panel-title { + @apply leading-none font-semibold +} + +.p-panel-content { + @apply pt-0 pb-[1.125rem] px-[1.125rem] +} + +.p-panel-footer { + @apply pt-0 pb-[1.125rem] px-[1.125rem] +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/panelmenu.css b/frontend/packages/kwai-ui/src/css/primevue/panelmenu.css new file mode 100644 index 000000000..77f28503b --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/panelmenu.css @@ -0,0 +1,94 @@ +.p-panelmenu { + @apply flex flex-col gap-2 +} + +.p-panelmenu-panel { + @apply bg-surface-0 dark:bg-surface-900 rounded-md p-1 + border border-surface-200 dark:border-surface-700 + text-surface-700 dark:text-surface-0 +} + +.p-panelmenu-header { + @apply outline-none +} + +.p-panelmenu-header-content { + @apply rounded-md transition-colors duration-200 text-surface-700 dark:text-surface-0 +} + +.p-panelmenu-header-link { + @apply flex items-center gap-2 px-3 py-2 select-none cursor-pointer relative no-underline text-inherit +} + +.p-panelmenu-header-icon, +.p-panelmenu-item-icon { + @apply text-surface-400 dark:text-surface-500 +} + +.p-panelmenu-submenu-icon { + @apply text-surface-400 dark:text-surface-500 +} + +.p-panelmenu-header:not(.p-disabled):focus-visible .p-panelmenu-header-content { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-panelmenu-header:not(.p-disabled):focus-visible .p-panelmenu-header-content .p-panelmenu-header-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-panelmenu-header:not(.p-disabled):focus-visible .p-panelmenu-header-content .p-panelmenu-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-panelmenu-header:not(.p-panelmenu-header-active) .p-panelmenu-submenu-icon:dir(rtl) { + @apply rotate-180; +} + +.p-panelmenu-header:not(.p-disabled) .p-panelmenu-header-content:hover { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-panelmenu-header:not(.p-disabled) .p-panelmenu-header-content:hover .p-panelmenu-header-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-panelmenu-header:not(.p-disabled) .p-panelmenu-header-content:hover .p-panelmenu-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-panelmenu-submenu { + @apply m-0 py-0 ps-4 outline-none list-none +} + +.p-panelmenu-item-link { + @apply flex items-center gap-2 px-3 py-2 select-none cursor-pointer no-underline text-inherit relative overflow-hidden +} + +.p-panelmenu-item-content { + @apply rounded-md transition-colors duration-200 text-surface-700 dark:text-surface-0 +} + +.p-panelmenu-item.p-focus > .p-panelmenu-item-content { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-panelmenu-item.p-focus > .p-panelmenu-item-content .p-panelmenu-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-panelmenu-item.p-focus > .p-panelmenu-item-content .p-panelmenu-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-panelmenu-item:not(.p-disabled) > .p-panelmenu-item-content:hover { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-panelmenu-item:not(.p-disabled) > .p-panelmenu-item-content:hover .p-panelmenu-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-panelmenu-item:not(.p-disabled) > .p-panelmenu-item-content:hover .p-panelmenu-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/password.css b/frontend/packages/kwai-ui/src/css/primevue/password.css new file mode 100644 index 000000000..e350fcbab --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/password.css @@ -0,0 +1,61 @@ +@import './inputtext'; + +.p-password { + @apply inline-flex relative +} + +.p-password .p-password-overlay { + @apply min-w-full +} + +.p-password-meter { + @apply h-3 bg-surface-200 dark:bg-surface-700 rounded-md +} + +.p-password-meter-label { + @apply h-full w-0 transition-[width] duration-1000 ease-in-out rounded-md +} + +.p-password-meter-weak { + @apply bg-red-500 dark:bg-red-400 +} + +.p-password-meter-medium { + @apply bg-amber-500 dark:bg-amber-400 +} + +.p-password-meter-strong { + @apply bg-green-500 dark:bg-green-400 +} + +.p-password-fluid { + @apply flex +} + +.p-password-fluid .p-password-input { + @apply w-full +} + +.p-password-input::-ms-reveal, +.p-password-input::-ms-clear { + @apply hidden +} + +.p-password-overlay { + @apply p-3 rounded-md bg-surface-0 dark:bg-surface-900 + border border-surface-200 dark:border-surface-700 + text-surface-700 dark:text-surface-0 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-password-content { + @apply flex flex-col gap-2 +} + +.p-password-toggle-mask-icon { + @apply end-3 text-surface-500 dark:text-surface-400 absolute top-1/2 -mt-2 w-4 h-4 +} + +.p-password:has(.p-password-toggle-mask-icon) .p-password-input { + @apply pe-10 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/picklist.css b/frontend/packages/kwai-ui/src/css/primevue/picklist.css new file mode 100644 index 000000000..0dec3454d --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/picklist.css @@ -0,0 +1,18 @@ +@import './button'; +@import './listbox'; + +.p-picklist { + @apply flex gap-[1.125rem] +} + +.p-picklist-controls { + @apply flex flex-col justify-center gap-2 +} + +.p-picklist-list-container { + @apply flex-grow flex-shrink basis-1/2 +} + +.p-picklist .p-listbox { + @apply h-full +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/popover.css b/frontend/packages/kwai-ui/src/css/primevue/popover.css new file mode 100644 index 000000000..964d2d9df --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/popover.css @@ -0,0 +1,46 @@ +.p-popover { + @apply mt-[10px] bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 + border border-surface-200 dark:border-surface-700 + rounded-md shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] + before:bottom-full before:left-5 before:h-0 before:w-0 before:absolute before:pointer-events-none + before:border-[10px] before:-ms-[10px] before:border-transparent before:border-b-surface-200 dark:before:border-b-surface-700 + after:bottom-full after:left-5 after:h-0 after:w-0 after:absolute after:pointer-events-none + after:border-[8px] after:-ms-[8px] after:border-transparent after:border-b-surface-0 dark:after:border-b-surface-900 +} + +.p-popover-content { + @apply p-3 +} + +.p-popover-flipped { + @apply -mt-[10px] mb-[10px] +} + +.p-popover-enter-from { + @apply opacity-0 scale-y-75 +} + +.p-popover-leave-to { + @apply opacity-0 +} + +.p-popover-enter-active { + @apply [transition:transform_120ms_cubic-bezier(0,0,0.2,1),opacity_120ms_cubic-bezier(0,0,0.2,1)] +} + +.p-popover-leave-active { + @apply transition-opacity duration-100 ease-linear +} + +.p-popover-flipped:after, +.p-popover-flipped:before { + @apply bottom-auto top-full +} + +.p-popover.p-popover-flipped:after { + @apply border-b-transparent border-t-surface-0 dark:border-t-surface-900 +} + +.p-popover.p-popover-flipped:before { + @apply border-b-transparent border-t-surface-200 dark:border-t-surface-700 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/progressbar.css b/frontend/packages/kwai-ui/src/css/primevue/progressbar.css new file mode 100644 index 000000000..3788b236f --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/progressbar.css @@ -0,0 +1,67 @@ +.p-progressbar { + @apply relative overflow-hidden h-5 bg-surface-200 dark:bg-surface-700 rounded-md +} + +.p-progressbar-value { + @apply m-0 bg-primary +} + +.p-progressbar-label { + @apply text-primary-contrast text-xs font-semibold +} + +.p-progressbar-determinate .p-progressbar-value { + @apply h-full w-0 absolute flex items-center justify-center overflow-hidden transition-[width] duration-1000 ease-in-out +} + +.p-progressbar-determinate .p-progressbar-label { + @apply inline-flex +} + +.p-progressbar-indeterminate .p-progressbar-value::before { + @apply content-[''] absolute bg-inherit top-0 start-0 bottom-0 will-change-[inset-inline-start,inset-inline-end]; +} + +.p-progressbar-indeterminate .p-progressbar-value::before { + animation: p-progressbar-indeterminate-anim 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; +} + +.p-progressbar-indeterminate .p-progressbar-value::after { + @apply content-[''] absolute bg-inherit top-0 start-0 bottom-0 will-change-[inset-inline-start,inset-inline-end]; + +} + +.p-progressbar-indeterminate .p-progressbar-value::after { + animation: p-progressbar-indeterminate-anim-short 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) infinite; + animation-delay: 1.15s; +} + +@keyframes p-progressbar-indeterminate-anim { + 0% { + inset-inline-start: -35%; + inset-inline-end: 100%; + } + 60% { + inset-inline-start: 100%; + inset-inline-end: -90%; + } + 100% { + inset-inline-start: 100%; + inset-inline-end: -90%; + } +} + +@keyframes p-progressbar-indeterminate-anim-short { + 0% { + inset-inline-start: -200%; + inset-inline-end: 100%; + } + 60% { + inset-inline-start: 107%; + inset-inline-end: -8%; + } + 100% { + inset-inline-start: 107%; + inset-inline-end: -8%; + } +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/progressspinner.css b/frontend/packages/kwai-ui/src/css/primevue/progressspinner.css new file mode 100644 index 000000000..335abd177 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/progressspinner.css @@ -0,0 +1,58 @@ +.p-progressspinner { + @apply relative my-0 mx-auto w-[100px] h-[100px] inline-block + before:block before:pt-[100%] +} + +.p-progressspinner-spin { + @apply h-full origin-center w-full absolute top-0 bottom-0 start-0 end-0 m-auto; +} + +.p-progressspinner-spin { + animation: p-progressspinner-rotate 2s linear infinite; +} + +.p-progressspinner-circle { + stroke-dasharray: 89, 200; + stroke-dashoffset: 0; + stroke: theme(colors.red.500); + stroke-linecap: round; + animation: p-progressspinner-dash 1.5s ease-in-out infinite, p-progressspinner-color 6s ease-in-out infinite; +} + +@keyframes p-progressspinner-rotate { + 100% { + transform: rotate(360deg); + } +} + +@keyframes p-progressspinner-dash { + 0% { + stroke-dasharray: 1, 200; + stroke-dashoffset: 0; + } + 50% { + stroke-dasharray: 89, 200; + stroke-dashoffset: -35px; + } + 100% { + stroke-dasharray: 89, 200; + stroke-dashoffset: -124px; + } +} + +@keyframes p-progressspinner-color { + 100%, + 0% { + stroke: theme(colors.red.500); + } + 40% { + stroke: theme(colors.blue.500); + } + 66% { + stroke: theme(colors.green.500); + } + 80%, + 90% { + stroke: theme(colors.yellow.500); + } +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/radiobutton.css b/frontend/packages/kwai-ui/src/css/primevue/radiobutton.css new file mode 100644 index 000000000..bd88f93da --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/radiobutton.css @@ -0,0 +1,93 @@ +.p-radiobutton { + @apply relative inline-flex select-none w-5 h-5 +} + +.p-radiobutton-input { + @apply cursor-pointer disabled:cursor-default appearance-none absolute start-0 top-0 w-full h-full m-0 p-0 opacity-0 z-10 + border border-transparent rounded-full +} + +.p-radiobutton-box { + @apply flex justify-center items-center rounded-full + border border-surface-300 dark:border-surface-700 + bg-surface-0 dark:bg-surface-950 + w-5 h-5 + transition-colors duration-200 + shadow-[0_1px_2px_0_rgba(18,18,23,0.05)] +} + +.p-radiobutton-icon { + @apply bg-transparent text-xs w-3 h-3 rounded-full + transition-all duration-200 backface-hidden +} + +.p-radiobutton-icon { + @apply scale-[0.1] +} + +.p-radiobutton:not(.p-disabled):has(.p-radiobutton-input:hover) .p-radiobutton-box { + @apply border-surface-400 dark:border-surface-600 +} + +.p-radiobutton-checked .p-radiobutton-box { + @apply border-primary bg-primary +} + +.p-radiobutton-checked .p-radiobutton-box .p-radiobutton-icon { + @apply bg-primary-contrast visible +} + +.p-radiobutton-checked .p-radiobutton-box .p-radiobutton-icon { + @apply scale-100 +} + +.p-radiobutton-checked:not(.p-disabled):has(.p-radiobutton-input:hover) .p-radiobutton-box { + @apply border-primary-emphasis bg-primary-emphasis +} + +.p-radiobutton:not(.p-disabled):has(.p-radiobutton-input:hover).p-radiobutton-checked .p-radiobutton-box .p-radiobutton-icon { + @apply bg-primary-contrast +} + +.p-radiobutton:not(.p-disabled):has(.p-radiobutton-input:focus-visible) .p-radiobutton-box { + @apply outline outline-1 outline-offset-2 outline-primary +} + +.p-radiobutton.p-invalid > .p-radiobutton-box { + @apply border-red-400 dark:border-red-300 +} + +.p-radiobutton.p-variant-filled .p-radiobutton-box { + @apply bg-surface-50 dark:bg-surface-800 +} + +.p-radiobutton.p-disabled { + @apply opacity-100 +} + +.p-radiobutton.p-disabled .p-radiobutton-box { + @apply bg-surface-200 dark:bg-surface-400 + border-surface-300 dark:border-surface-700 +} + +.p-radiobutton-checked.p-disabled .p-radiobutton-box .p-radiobutton-icon { + @apply bg-surface-700 dark:bg-surface-400 +} + +.p-radiobutton-sm, +.p-radiobutton-sm .p-radiobutton-box { + @apply w-4 h-4 +} + +.p-radiobutton-sm .p-radiobutton-icon { + @apply w-2 h-2 +} + +.p-radiobutton-lg, +.p-radiobutton-lg .p-radiobutton-box { + @apply w-6 h-6 +} + +.p-radiobutton-lg .p-radiobutton-icon { + @apply w-4 h-4 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/rating.css b/frontend/packages/kwai-ui/src/css/primevue/rating.css new file mode 100644 index 000000000..61cc30843 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/rating.css @@ -0,0 +1,23 @@ +.p-rating { + @apply relative flex items-center gap-1 +} + +.p-rating-option { + @apply inline-flex items-center cursor-pointer rounded-full +} + +.p-rating-option.p-focus-visible { + @apply outline outline-1 outline-offset-2 outline-primary +} + +.p-rating-icon { + @apply text-surface-500 dark:text-surface-400 text-base w-4 h-4 transition-colors duration-200 +} + +.p-rating:not(.p-disabled):not(.p-readonly) .p-rating-option:hover .p-rating-icon { + @apply text-primary +} + +.p-rating-option-active .p-rating-icon { + @apply text-primary +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/ripple.css b/frontend/packages/kwai-ui/src/css/primevue/ripple.css new file mode 100644 index 000000000..a40d975c6 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/ripple.css @@ -0,0 +1,7 @@ +.p-ink { + @apply block absolute bg-black/10 dark:bg-white/30 scale-0 rounded-[100%] pointer-events-none +} + +.p-ink-active { + @apply transition-[opacity,transform] duration-500 scale-[2.5] opacity-0 ease-linear +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/scrollpanel.css b/frontend/packages/kwai-ui/src/css/primevue/scrollpanel.css new file mode 100644 index 000000000..8bf7fd55c --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/scrollpanel.css @@ -0,0 +1,41 @@ +.p-scrollpanel-content-container { + @apply overflow-hidden w-full h-full relative z-10 float-left +} + +.p-scrollpanel-content { + @apply relative overflow-auto + h-[calc(100%+18px)] w-[calc(100%+18px)] + pt-0 ps-0 pr-[18px] pb-[18px] [scrollbar-width:none] +} + +.p-scrollpanel-content::-webkit-scrollbar { + @apply hidden +} + +.p-scrollpanel-bar { + @apply relative rounded-sm z-20 cursor-pointer opacity-0 + bg-surface-100 dark:bg-surface-800 + transition-opacity duration-200 border-none + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-scrollpanel-bar-y { + @apply w-[9px] top-0 +} + +.p-scrollpanel-bar-x { + @apply h-[9px] bottom-0 +} + +.p-scrollpanel-hidden { + @apply invisible +} + +.p-scrollpanel:hover .p-scrollpanel-bar, +.p-scrollpanel:active .p-scrollpanel-bar { + @apply opacity-100 +} + +.p-scrollpanel-grabbed { + @apply select-none +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/scrolltop.css b/frontend/packages/kwai-ui/src/css/primevue/scrolltop.css new file mode 100644 index 000000000..40e5381f4 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/scrolltop.css @@ -0,0 +1,25 @@ +@import './button'; + +.p-scrolltop.p-button { + @apply fixed bottom-5 end-5 +} + +.p-scrolltop-sticky.p-button { + @apply sticky flex ms-auto +} + +.p-scrolltop-enter-from { + @apply opacity-0 +} + +.p-scrolltop-enter-active { + @apply transition-opacity duration-150 +} + +.p-scrolltop.p-scrolltop-leave-to { + @apply opacity-0 +} + +.p-scrolltop-leave-active { + @apply transition-opacity duration-150 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/select.css b/frontend/packages/kwai-ui/src/css/primevue/select.css new file mode 100644 index 000000000..85b108e83 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/select.css @@ -0,0 +1,144 @@ +@import './button'; +@import './inputtext'; +@import './iconfield'; + +.p-select { + @apply inline-flex cursor-pointer relative select-none rounded-md + bg-surface-0 dark:bg-surface-950 + border border-surface-300 dark:border-surface-700 + shadow-[0_1px_2px_0_rgba(18,18,23,0.05)] + transition-colors duration-200 +} + +.p-select:not(.p-disabled):hover { + @apply border-surface-400 dark:border-surface-600 +} + +.p-select:not(.p-disabled).p-focus { + @apply border-primary +} + +.p-select.p-variant-filled { + @apply bg-surface-50 dark:bg-surface-800 +} + +.p-select.p-invalid { + @apply border-red-400 dark:border-red-300 +} + +.p-select.p-disabled { + @apply bg-surface-200 text-surface-500 dark:bg-surface-700 dark:text-surface-400 opacity-100 cursor-default +} + +.p-select-clear-icon { + @apply absolute top-1/2 -mt-2 text-surface-500 dark:text-surface-400 end-10 +} + +.p-select-dropdown { + @apply flex items-center justify-center shrink-0 bg-transparent + text-surface-500 dark:text-surface-400 w-10 rounded-e-md +} + +.p-select-label { + @apply block whitespace-nowrap overflow-hidden flex-auto w-[1%] + py-2 px-3 overflow-ellipsis + text-surface-700 dark:text-surface-0 bg-transparent border-none outline-none +} + +.p-select-label.p-placeholder { + @apply text-surface-500 dark:text-surface-400 +} + +.p-select:has(.p-select-clear-icon) .p-select-label { + @apply pe-7 +} + +.p-select.p-disabled .p-select-label { + @apply text-surface-500 dark:text-surface-400 +} + +.p-select-label-empty { + @apply overflow-hidden opacity-0 +} + +input.p-select-label { + @apply cursor-default +} + +.p-select .p-select-overlay { + @apply min-w-full +} + +.p-select-overlay { + @apply absolute top-0 left-0 rounded-md + bg-surface-0 dark:bg-surface-900 + border border-surface-200 dark:border-surface-700 + text-surface-700 dark:text-surface-0 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-select-header { + @apply pt-2 pb-1 px-4 +} + +.p-select-filter { + @apply w-full +} + +.p-select-list-container { + @apply overflow-auto +} + +.p-select-option-group { + @apply m-0 px-3 py-2 bg-transparent text-surface-500 dark:text-surface-400 font-semibold +} + +.p-select-list { + @apply m-0 p-1 list-none gap-[2px] flex flex-col +} + +.p-select-option { + @apply cursor-pointer font-normal whitespace-nowrap relative overflow-hidden flex items-center + px-3 py-2 border-none text-surface-700 dark:text-surface-0 bg-transparent rounded-sm + transition-colors duration-200 +} + +.p-select-option:not(.p-select-option-selected):not(.p-disabled).p-focus { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-select-option.p-select-option-selected { + @apply bg-highlight +} + +.p-select-option.p-select-option-selected.p-focus { + @apply bg-highlight-emphasis +} + +.p-select-option-check-icon { + @apply relative -ms-[0.375rem] me-[0.375rem] text-surface-700 dark:text-surface-0 +} + +.p-select-empty-message { + @apply px-3 py-2 +} + +.p-select-fluid { + @apply flex +} + +.p-select-sm .p-select-label { + @apply text-sm px-[0.625rem] py-[0.375rem] +} + +.p-select-sm .p-select-dropdown .p-icon { + @apply text-sm w-[0.875rem] h-[0.875rem] +} + +.p-select-lg .p-select-label { + @apply text-lg px-[0.875rem] py-[0.625rem] +} + +.p-select-lg .p-select-dropdown .p-icon { + @apply text-lg w-[1.125rem] h-[1.125rem] +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/selectbutton.css b/frontend/packages/kwai-ui/src/css/primevue/selectbutton.css new file mode 100644 index 000000000..5350fdeef --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/selectbutton.css @@ -0,0 +1,25 @@ +@import './togglebutton'; + +.p-selectbutton { + @apply inline-flex select-none rounded-md +} + +.p-selectbutton .p-togglebutton { + @apply rounded-none border-y border-r border-s-0 +} + +.p-selectbutton .p-togglebutton:focus-visible { + @apply relative z-10 +} + +.p-selectbutton .p-togglebutton:first-child { + @apply border-s rounded-s-md +} + +.p-selectbutton .p-togglebutton:last-child { + @apply rounded-e-md +} + +.p-selectbutton.p-invalid { + @apply outline outline-offset-0 outline-red-400 dark:outline-red-300 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/skeleton.css b/frontend/packages/kwai-ui/src/css/primevue/skeleton.css new file mode 100644 index 000000000..e2393cd21 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/skeleton.css @@ -0,0 +1,11 @@ +.p-skeleton { + @apply overflow-hidden bg-surface-200 dark:bg-surface-700 animate-pulse rounded-md +} + +.p-skeleton-circle { + @apply rounded-full +} + +.p-skeleton-animation-none::after { + @apply animate-none +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/slider.css b/frontend/packages/kwai-ui/src/css/primevue/slider.css new file mode 100644 index 000000000..ae3b9718b --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/slider.css @@ -0,0 +1,42 @@ +.p-slider { + @apply relative bg-surface-200 dark:bg-surface-700 rounded-sm +} + +.p-slider-handle { + @apply cursor-grab touch-none flex items-center justify-center h-[20px] w-[20px] + bg-surface-200 dark:bg-surface-700 rounded-full + transition-colors duration-200 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary + before:w-[16px] before:h-[16px] before:block before:rounded-full + before:bg-surface-0 dark:before:bg-surface-950 + before:shadow-[0px_0.5px_0px_0px_rgba(0,0,0,0.08),0px_1px_1px_0px_rgba(0,0,0,0.14)] + before:transition-colors before:duration-200 +} + +.p-slider-range { + @apply block bg-primary rounded-sm +} + +.p-slider.p-slider-horizontal { + @apply h-[3px] +} + +.p-slider-horizontal .p-slider-range { + @apply top-0 start-0 h-full +} + +.p-slider-horizontal .p-slider-handle { + @apply top-1/2 -mt-[10px] -ms-[10px] +} + +.p-slider-vertical { + @apply min-h-[100px] w-[3px] +} + +.p-slider-vertical .p-slider-handle { + @apply start-1/2 -mb-[10px] -ms-[10px] +} + +.p-slider-vertical .p-slider-range { + @apply bottom-0 start-0 w-full +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/speeddial.css b/frontend/packages/kwai-ui/src/css/primevue/speeddial.css new file mode 100644 index 000000000..a9f3c4692 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/speeddial.css @@ -0,0 +1,48 @@ +@import './button'; + +.p-speeddial { + @apply static flex gap-2 +} + +.p-speeddial-button { + @apply z-10 +} + +.p-speeddial-button.p-speeddial-rotate { + @apply [transition:transform_250ms_cubic-bezier(0.4,0,0.2,1)_0ms,background_200ms,color_200ms,border-color_200ms] will-change-transform +} + +.p-speeddial-list { + @apply m-0 p-0 list-none flex items-center justify-center pointer-events-none outline-none z-20 gap-2 + transition-[top] ease-linear duration-200 +} + +.p-speeddial-item { + @apply scale-0 opacity-0 [transition:transform_200ms_cubic-bezier(0.4,0,0.2,1)_0ms,opacity_0.8s] will-change-transform +} + +.p-speeddial-circle .p-speeddial-item, +.p-speeddial-semi-circle .p-speeddial-item, +.p-speeddial-quarter-circle .p-speeddial-item { + @apply absolute +} + +.p-speeddial-mask { + @apply absolute start-0 top-0 w-full h-full opacity-0 bg-white/40 dark:bg-white/60 rounded-md transition-opacity duration-150 +} + +.p-speeddial-mask-visible { + @apply pointer-events-none opacity-100 transition-opacity duration-150 +} + +.p-speeddial-open .p-speeddial-list { + @apply pointer-events-auto +} + +.p-speeddial-open .p-speeddial-item { + @apply scale-100 opacity-100 +} + +.p-speeddial-open .p-speeddial-rotate { + @apply rotate-45 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/splitbutton.css b/frontend/packages/kwai-ui/src/css/primevue/splitbutton.css new file mode 100644 index 000000000..cf0cd0a49 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/splitbutton.css @@ -0,0 +1,34 @@ +@import './button'; +@import './tieredmenu'; + +.p-splitbutton { + @apply inline-flex relative rounded-md +} + +.p-splitbutton-button { + @apply rounded-e-none border-r-0 enabled:hover:border-r-0 enabled:active:border-r-0 focus-visible:z-10 +} + +.p-splitbutton-dropdown { + @apply rounded-s-none focus-visible:z-10 +} + +.p-splitbutton .p-menu { + @apply min-w-full +} + +.p-splitbutton-fluid { + @apply w-full +} + +.p-splitbutton-rounded .p-splitbutton-dropdown { + @apply rounded-e-[2rem] +} + +.p-splitbutton-rounded .p-splitbutton-button { + @apply rounded-s-[2rem] +} + +.p-splitbutton-raised { + @apply shadow-[0_3px_1px_-2px_rgba(0,0,0,0.2),0_2px_2px_0_rgba(0,0,0,0.14),0_1px_5px_0_rgba(0,0,0,0.12)] +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/splitter.css b/frontend/packages/kwai-ui/src/css/primevue/splitter.css new file mode 100644 index 000000000..f6915f564 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/splitter.css @@ -0,0 +1,56 @@ +.p-splitter { + @apply flex flex-wrap + border border-surface-200 dark:border-surface-700 rounded-md + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 +} + +.p-splitter-vertical { + @apply flex-col +} + +.p-splitter-gutter { + @apply flex-grow-0 flex-shrink-0 flex items-center justify-center z-10 bg-surface-200 dark:bg-surface-700 +} + +.p-splitter-gutter-handle { + @apply rounded-md bg-transparent + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary + transition-colors duration-200 +} + +.p-splitter-horizontal.p-splitter-resizing { + @apply cursor-col-resize select-none +} + +.p-splitter-vertical.p-splitter-resizing { + @apply cursor-row-resize select-none +} + +.p-splitter-horizontal > .p-splitter-gutter > .p-splitter-gutter-handle { + @apply h-[24px] w-full +} + +.p-splitter-vertical > .p-splitter-gutter > .p-splitter-gutter-handle { + @apply w-[24px] h-full +} + +.p-splitter-horizontal > .p-splitter-gutter { + @apply cursor-col-resize +} + +.p-splitter-vertical > .p-splitter-gutter { + @apply cursor-row-resize +} + +.p-splitterpanel { + @apply flex-grow overflow-hidden +} + +.p-splitterpanel-nested { + @apply flex +} + +.p-splitterpanel .p-splitter { + @apply flex-grow border-none +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/stepper.css b/frontend/packages/kwai-ui/src/css/primevue/stepper.css new file mode 100644 index 000000000..43f44e75e --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/stepper.css @@ -0,0 +1,102 @@ +.p-steplist { + @apply relative flex justify-between items-center m-0 p-0 list-none overflow-x-auto +} + +.p-step { + @apply relative flex flex-auto items-center gap-4 p-2 last-of-type:flex-initial +} + +.p-step-header { + @apply border-none inline-flex items-center no-underline cursor-pointer + transition-colors duration-200 rounded-md bg-transparent p-0 gap-2 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary +} + +.p-step.p-disabled .p-step-header { + @apply cursor-default +} + + +.p-stepper.p-stepper-readonly .p-step { + @apply cursor-auto +} + +.p-step-title { + @apply block whitespace-nowrap overflow-hidden text-ellipsis max-w-full + text-surface-500 dark:text-surface-400 font-medium transition-colors duration-200 +} + +.p-step-number { + @apply flex items-center justify-center text-surface-500 dark:text-surface-400 + bg-surface-0 dark:bg-surface-900 border-2 border-surface-200 dark:border-surface-700 + min-w-8 h-8 leading-8 text-lg font-medium rounded-full z-10 relative + after:absolute after:w-full after:h-full after:rounded-full after:shadow-[0px_0.5px_0px_0px_rgba(0,0,0,0.06),0px_1px_1px_0px_rgba(0,0,0,0.12)] +} + +.p-step-active .p-step-header { + @apply cursor-default +} + +.p-step-active .p-step-number { + @apply bg-surface-0 dark:bg-surface-900 text-primary border-surface-200 dark:border-surface-700 +} + +.p-step-active .p-step-title { + @apply text-primary +} + +.p-step:not(.p-disabled):focus-visible { + @apply outline outline-1 outline-offset-2 outline-primary +} + +.p-step:has(~ .p-step-active) .p-stepper-separator { + @apply bg-primary +} + +.p-stepper-separator { + @apply flex-1 bg-surface-200 dark:bg-surface-700 w-full h-[2px] transition-colors duration-200 +} + +.p-steppanels { + @apply pt-[0.875rem] pb-[1.125rem] px-2 +} + +.p-steppanel { + @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 +} + +.p-stepper:has(.p-stepitem) { + @apply flex flex-col +} + +.p-stepitem { + @apply flex flex-col flex-initial +} + +.p-stepitem.p-stepitem-active { + @apply flex-auto +} + +.p-stepitem .p-step { + @apply flex-initial +} + +.p-stepitem .p-steppanel-content { + @apply w-full ps-4 +} + +.p-stepitem .p-steppanel { + @apply flex flex-auto +} + +.p-stepitem .p-stepper-separator { + @apply flex-grow-0 flex-shrink-0 basis-auto w-[2px] h-auto ms-[1.625rem] relative start-[-2.5px] +} + +.p-stepitem:has(~ .p-stepitem-active) .p-stepper-separator { + @apply bg-primary +} + +.p-stepitem:last-of-type .p-steppanel { + @apply ps-8 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/tabs.css b/frontend/packages/kwai-ui/src/css/primevue/tabs.css new file mode 100644 index 000000000..0ac004ba9 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/tabs.css @@ -0,0 +1,84 @@ +.p-tabs { + @apply flex flex-col +} + +.p-tablist { + @apply flex relative +} + +.p-tabs-scrollable > .p-tablist { + @apply overflow-hidden +} + +.p-tablist-viewport { + @apply overflow-x-auto overflow-y-hidden overscroll-y-contain overscroll-x-auto +} + +.p-tablist-viewport::-webkit-scrollbar { + @apply hidden +} + +.p-tablist-tab-list { + @apply relative flex bg-surface-0 dark:bg-surface-900 border-b border-surface-200 dark:border-surface-700 +} + +.p-tablist-content { + @apply flex-grow +} + +.p-tablist-nav-button { + @apply !absolute flex-shrink-0 top-0 z-20 h-full flex items-center justify-center cursor-pointer + bg-surface-0 dark:bg-surface-900 text-surface-500 dark:text-surface-400 hover:text-surface-700 dark:hover:text-surface-0 w-10 + shadow-[0px_0px_10px_50px_rgba(255,255,255,0.6)] dark:shadow-[0px_0px_10px_50px] dark:shadow-surface-900/50 + focus-visible:z-10 focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-[-1px] focus-visible:outline-primary + transition-colors duration-200 +} + +.p-tablist-prev-button { + @apply start-0 +} + +.p-tablist-next-button { + @apply end-0 +} + +.p-tablist-prev-button:dir(rtl), +.p-tablist-next-button:dir(rtl) { + @apply rotate-180 +} + +.p-tab { + @apply flex-shrink-0 cursor-pointer select-none relative whitespace-nowrap py-4 px-[1.125rem] + border-b border-surface-200 dark:border-surface-700 font-semibold + text-surface-500 dark:text-surface-400 + transition-colors duration-200 -mb-px +} + +.p-tab.p-disabled { + @apply cursor-default +} + +.p-tab:not(.p-disabled):focus-visible { + @apply z-10 outline outline-1 outline-offset-[-1px] outline-primary +} + +.p-tab:not(.p-tab-active):not(.p-disabled):hover { + @apply text-surface-700 dark:text-surface-0 +} + +.p-tab-active { + @apply border-primary text-primary +} + +.p-tabpanels { + @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 + pt-[0.875rem] pb-[1.125rem] px-[1.125rem] outline-none +} + +.p-tablist-active-bar { + @apply z-10 block absolute -bottom-px h-px bg-primary transition-[left] duration-200 ease-[cubic-bezier(0.35,0,0.25,1)] +} + +.p-tablist-viewport { + @apply [scrollbar-behavior:smooth] [scrollbar-width:none] +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/tag.css b/frontend/packages/kwai-ui/src/css/primevue/tag.css new file mode 100644 index 000000000..8ef41faa2 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/tag.css @@ -0,0 +1,38 @@ +.p-tag { + @apply inline-flex items-center justify-center + bg-primary-100 dark:bg-primary-500/15 + text-primary-700 dark:text-primary-300 + text-sm font-bold py-1 px-2 rounded-md gap-1 +} + +.p-tag-icon { + @apply text-xs w-3 h-3 +} + +.p-tag-rounded { + @apply rounded-2xl +} + +.p-tag-success { + @apply bg-green-100 dark:bg-green-500/15 text-green-700 dark:text-green-300 +} + +.p-tag-info { + @apply bg-sky-100 dark:bg-sky-500/15 text-sky-700 dark:text-sky-300 +} + +.p-tag-warn { + @apply bg-orange-100 dark:bg-orange-500/15 text-orange-700 dark:text-orange-300 +} + +.p-tag-danger { + @apply bg-red-100 dark:bg-red-500/15 text-red-700 dark:text-red-300 +} + +.p-tag-secondary { + @apply bg-surface-100 dark:bg-surface-800 text-surface-600 dark:text-surface-300 +} + +.p-tag-contrast { + @apply bg-surface-950 dark:bg-surface-0 text-surface-0 dark:text-surface-950 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/tailwind.css b/frontend/packages/kwai-ui/src/css/primevue/tailwind.css new file mode 100644 index 000000000..7aec51300 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/tailwind.css @@ -0,0 +1,104 @@ +@import './common'; + +/* Form */ +@import './autocomplete'; +@import './cascadeselect'; +@import './checkbox'; +@import './colorpicker'; +@import './datepicker'; +@import './iconfield'; +@import './iftalabel'; +@import './inputgroup'; +@import './inputnumber'; +@import './inputotp'; +@import './inputtext'; +@import './floatlabel'; +@import './knob'; +@import './listbox'; +@import './multiselect'; +@import './password'; +@import './radiobutton'; +@import './rating'; +@import './select'; +@import './selectbutton'; +@import './slider'; +@import './textarea'; +@import './togglebutton'; +@import './toggleswitch'; +@import './treeselect'; + +/* Button */ +@import './button'; +@import './buttongroup'; +@import './speeddial'; +@import './splitbutton'; + +/* Data */ +@import './datatable'; +@import './dataview'; +@import './paginator'; +@import './picklist'; +@import './orderlist'; +@import './organizationchart'; +@import './timeline'; +@import './tree'; +@import './treetable'; + +/* Overlay */ +@import './confirmdialog'; +@import './confirmpopup'; +@import './dialog'; +@import './drawer'; +@import './popover'; +@import './tooltip'; + +/* Menu */ +@import './breadcrumb'; +@import './contextmenu'; +@import './dock'; +@import './menu'; +@import './menubar'; +@import './megamenu'; +@import './panelmenu'; +@import './tieredmenu'; + +/* Panel */ +@import './accordion'; +@import './card'; +@import './divider'; +@import './fieldset'; +@import './panel'; +@import './scrollpanel'; +@import './splitter'; +@import './stepper'; +@import './tabs'; +@import './toolbar'; + +/* File */ +@import './fileupload'; + +/* Message */ +@import './message'; +@import './toast'; + +/* Media */ +@import './carousel'; +@import './galleria'; +@import './image'; +@import './imagecompare'; + +/* Misc */ +@import './avatar'; +@import './badge'; +@import './blockui'; +@import './chip'; +@import './inplace'; +@import './metergroup'; +@import './overlaybadge'; +@import './progressbar'; +@import './progressspinner'; +@import './ripple'; +@import './scrolltop'; +@import './skeleton'; +@import './tag'; +@import './terminal'; diff --git a/frontend/packages/kwai-ui/src/css/primevue/terminal.css b/frontend/packages/kwai-ui/src/css/primevue/terminal.css new file mode 100644 index 000000000..71d107d69 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/terminal.css @@ -0,0 +1,22 @@ +.p-terminal { + @apply h-72 overflow-auto px-3 py-2 rounded-md + border border-surface-300 dark:border-surface-700 + bg-surface-0 dark:bg-surface-950 + text-surface-700 dark:text-surface-0 +} + +.p-terminal-prompt { + @apply flex items-center +} + +.p-terminal-prompt-value { + @apply flex-auto border-none bg-transparent text-inherit p-0 outline-none text-base +} + +.p-terminal-prompt-label { + @apply me-1 +} + +.p-terminal-input::-ms-clear { + @apply hidden +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/textarea.css b/frontend/packages/kwai-ui/src/css/primevue/textarea.css new file mode 100644 index 000000000..c5bb8fac5 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/textarea.css @@ -0,0 +1,38 @@ +.p-textarea { + @apply appearance-none rounded-md + border border-surface-300 dark:border-surface-700 + enabled:hover:border-surface-400 dark:enabled:hover:border-surface-600 + enabled:focus:border-primary + bg-surface-0 dark:bg-surface-950 + text-surface-700 dark:text-surface-0 + disabled:bg-surface-200 disabled:text-surface-500 disabled:opacity-100 dark:disabled:bg-surface-700 dark:disabled:text-surface-400 + placeholder:text-surface-500 dark:placeholder:text-surface-400 + px-3 py-2 + transition-colors duration-200 + shadow-[0_1px_2px_0_rgba(18,18,23,0.05)] + outline-none +} + +.p-textarea.p-invalid { + @apply border-red-400 dark:border-red-300 +} + +.p-textarea.p-variant-filled { + @apply bg-surface-50 dark:bg-surface-800 +} + +.p-textarea-fluid { + @apply w-full +} + +.p-textarea-resizable { + @apply overflow-hidden resize-none +} + +.p-textarea-sm { + @apply text-sm px-[0.625rem] py-[0.375rem] +} + +.p-textarea-lg { + @apply text-lg px-[0.875rem] py-[0.625rem] +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/tieredmenu.css b/frontend/packages/kwai-ui/src/css/primevue/tieredmenu.css new file mode 100644 index 000000000..900dea161 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/tieredmenu.css @@ -0,0 +1,105 @@ +.p-tieredmenu { + @apply bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + border border-surface-200 dark:border-surface-700 + rounded-md min-w-52 +} + +.p-tieredmenu-root-list, +.p-tieredmenu-submenu { + @apply m-0 p-1 list-none outline-none flex flex-col gap-[2px] +} + +.p-tieredmenu-submenu { + @apply absolute min-w-full z-10 rounded-md + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + border border-surface-200 dark:border-surface-700 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-tieredmenu-item { + @apply relative +} + +.p-tieredmenu-item-content { + @apply transition-colors duration-200 rounded-sm text-surface-700 dark:text-surface-0 +} + +.p-tieredmenu-item-link { + @apply cursor-pointer flex items-center no-underline overflow-hidden relative text-inherit + px-3 py-2 gap-2 select-none outline-none +} + +.p-tieredmenu-item-icon { + @apply text-surface-400 dark:text-surface-500 +} + +.p-tieredmenu-submenu-icon { + @apply text-surface-400 dark:text-surface-500 ms-auto text-sm w-[0.875rem] h-[0.875rem] +} + +.p-tieredmenu-item.p-focus > .p-tieredmenu-item-content { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-tieredmenu-item.p-focus > .p-tieredmenu-item-content .p-tieredmenu-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-tieredmenu-item.p-focus > .p-tieredmenu-item-content .p-tieredmenu-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-tieredmenu-item:not(.p-disabled) > .p-tieredmenu-item-content:hover { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-tieredmenu-item:not(.p-disabled) > .p-tieredmenu-item-content:hover .p-tieredmenu-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-tieredmenu-item:not(.p-disabled) > .p-tieredmenu-item-content:hover .p-tieredmenu-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-tieredmenu-item-active > .p-tieredmenu-item-content { + @apply bg-surface-100 dark:bg-surface-800 text-surface-800 dark:text-surface-0 +} + +.p-tieredmenu-item-active > .p-tieredmenu-item-content .p-tieredmenu-item-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-tieredmenu-item-active > .p-tieredmenu-item-content .p-tieredmenu-submenu-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-tieredmenu-separator { + @apply border-t border-surface-200 dark:border-surface-700 +} + +.p-tieredmenu-overlay { + @apply shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-tieredmenu-enter-from, +.p-tieredmenu-leave-active { + @apply opacity-0 +} + +.p-tieredmenu-enter-active { + @apply transition-opacity duration-[250ms] +} + +.p-tieredmenu-mobile .p-tieredmenu-submenu { + @apply static shadow-none border-none ps-4 pe-0 +} + +.p-tieredmenu-mobile .p-tieredmenu-submenu-icon { + @apply transition-transform duration-200 rotate-90 +} + +.p-tieredmenu-mobile .p-tieredmenu-item-active > .p-tieredmenu-item-content .p-tieredmenu-submenu-icon { + @apply -rotate-90 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/timeline.css b/frontend/packages/kwai-ui/src/css/primevue/timeline.css new file mode 100644 index 000000000..4d00cd472 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/timeline.css @@ -0,0 +1,113 @@ +.p-timeline { + @apply flex flex-col flex-grow +} + +.p-timeline-left .p-timeline-event-opposite { + @apply text-end +} + +.p-timeline-left .p-timeline-event-content { + @apply text-start +} + +.p-timeline-right .p-timeline-event { + @apply flex-row-reverse +} + +.p-timeline-right .p-timeline-event-opposite { + @apply text-start +} + +.p-timeline-right .p-timeline-event-content { + @apply text-end +} + +.p-timeline-vertical.p-timeline-alternate .p-timeline-event:nth-child(even) { + @apply flex-row-reverse +} + +.p-timeline-vertical.p-timeline-alternate .p-timeline-event:nth-child(odd) .p-timeline-event-opposite { + @apply text-end +} + +.p-timeline-vertical.p-timeline-alternate .p-timeline-event:nth-child(odd) .p-timeline-event-content { + @apply text-start +} + +.p-timeline-vertical.p-timeline-alternate .p-timeline-event:nth-child(even) .p-timeline-event-opposite { + @apply text-start +} + +.p-timeline-vertical.p-timeline-alternate .p-timeline-event:nth-child(even) .p-timeline-event-content { + @apply text-end +} + +.p-timeline-vertical .p-timeline-event-opposite, +.p-timeline-vertical .p-timeline-event-content { + @apply py-0 px-4 leading-none +} + +.p-timeline-vertical .p-timeline-event-connector { + @apply w-[2px] +} + +.p-timeline-event { + @apply flex relative min-h-20 last:min-h-0 +} + +.p-timeline-event-opposite { + @apply flex-1 +} + +.p-timeline-event-content { + @apply flex-1 +} + +.p-timeline-event-separator { + @apply flex-none flex flex-col items-center +} + +.p-timeline-event-marker { + @apply inline-flex items-center justify-center relative self-baseline + border-2 rounded-full border-surface-200 dark:border-surface-700 w-[1.125rem] h-[1.125rem] + bg-surface-0 dark:bg-surface-900 + before:rounded-full before:w-[0.375rem] before:h-[0.375rem] before:bg-primary + after:absolute after:w-full after:h-full after:rounded-full after:shadow-[0px_0.5px_0px_0px_rgba(0,0,0,0.06),0px_1px_1px_0px_rgba(0,0,0,0.12)] +} + +.p-timeline-event-connector { + @apply flex-grow bg-surface-200 dark:bg-surface-700 +} + +.p-timeline-horizontal { + @apply flex-row +} + +.p-timeline-horizontal .p-timeline-event { + @apply flex-col flex-1 +} + +.p-timeline-horizontal .p-timeline-event:last-child { + @apply flex-none +} + +.p-timeline-horizontal .p-timeline-event-separator { + @apply flex-row +} + +.p-timeline-horizontal .p-timeline-event-connector { + @apply w-full h-[2px] +} + +.p-timeline-horizontal .p-timeline-event-opposite, +.p-timeline-horizontal .p-timeline-event-content { + @apply py-4 px-0 +} + +.p-timeline-horizontal.p-timeline-alternate .p-timeline-event:nth-child(even) { + @apply flex-col-reverse +} + +.p-timeline-bottom .p-timeline-event { + @apply flex-col-reverse +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/toast.css b/frontend/packages/kwai-ui/src/css/primevue/toast.css new file mode 100644 index 000000000..c2b013f86 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/toast.css @@ -0,0 +1,172 @@ +.p-toast { + @apply w-96 rounded-md whitespace-pre-line break-words +} + +.p-toast-message { + @apply mb-4 +} + +.p-toast-message-icon { + @apply flex-shrink-0 text-lg w-[1.125rem] h-[1.125rem] +} + +.p-toast-message-content { + @apply flex items-start p-3 gap-2 +} + +.p-toast-message-text { + @apply flex-auto flex flex-col gap-2 +} + +.p-toast-summary { + @apply font-medium text-base +} + +.p-toast-detail { + @apply font-medium text-sm +} + +.p-toast-close-button { + @apply flex items-center justify-center overflow-hidden relative cursor-pointer bg-transparent select-none + transition-colors duration-200 text-inherit w-7 h-7 rounded-full -mt-[25%] -end-1/4 p-0 border-none + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 +} + +.p-toast-close-button:dir(rtl) { + @apply ms-auto end-auto +} + +.p-toast-message-info, +.p-toast-message-success, +.p-toast-message-warn, +.p-toast-message-error, +.p-toast-message-secondary, +.p-toast-message-contrast { + @apply border backdrop-blur-sm dark:backdrop-blur-md rounded-md +} + +.p-toast-close-icon { + @apply text-base w-4 h-4 +} + +.p-toast-message-info { + @apply bg-blue-50/95 border-blue-200 text-blue-600 + dark:bg-blue-500/15 dark:border-blue-700/35 dark:text-blue-500 + shadow-[0px_4px_8px_0px_theme(colors.blue.500/0.04)] +} + +.p-toast-message-info .p-toast-detail { + @apply text-surface-700 dark:text-surface-0 +} + +.p-toast-message-info .p-toast-close-button { + @apply hover:bg-blue-100 focus-visible:outline-blue-600 + dark:hover:bg-white/5 dark:focus-visible:outline-blue-500 +} + +.p-toast-message-success { + @apply bg-green-50/95 border-green-200 text-green-600 + dark:bg-green-500/15 dark:border-green-700/35 dark:text-green-500 + shadow-[0px_4px_8px_0px_theme(colors.green.500/0.04)] +} + +.p-toast-message-success .p-toast-detail { + @apply text-surface-700 dark:text-surface-0 +} + +.p-toast-message-success .p-toast-close-button { + @apply hover:bg-green-100 focus-visible:outline-green-600 + dark:hover:bg-white/5 dark:focus-visible:outline-green-500 +} + +.p-toast-message-warn { + @apply bg-yellow-50/95 border-yellow-200 text-yellow-600 + dark:bg-yellow-500/15 dark:border-yellow-700/35 dark:text-yellow-500 + shadow-[0px_4px_8px_0px_theme(colors.yellow.500/0.04)] +} + +.p-toast-message-warn .p-toast-detail { + @apply text-surface-700 dark:text-surface-0 +} + +.p-toast-message-warn .p-toast-close-button { + @apply hover:bg-yellow-100 focus-visible:outline-yellow-600 + dark:hover:bg-white/5 dark:focus-visible:outline-yellow-500 +} + +.p-toast-message-error { + @apply bg-red-50/95 border-red-200 text-red-600 + dark:bg-red-500/15 dark:border-red-700/35 dark:text-red-500 + shadow-[0px_4px_8px_0px_theme(colors.blue.500/0.04)] +} + +.p-toast-message-error .p-toast-detail { + @apply text-surface-700 dark:text-surface-0 +} + +.p-toast-message-error .p-toast-close-button { + @apply hover:bg-red-100 focus-visible:outline-red-600 + dark:hover:bg-white/5 dark:focus-visible:outline-red-500 +} + +.p-toast-message-secondary { + @apply bg-surface-100 border-surface-200 text-surface-600 + dark:bg-surface-800 dark:border-surface-700 dark:text-surface-300 + shadow-[0px_4px_8px_0px_rgba(0,0,0,0.04)] +} + +.p-toast-message-secondary .p-toast-detail { + @apply text-surface-700 dark:text-surface-0 +} + +.p-toast-message-secondary .p-toast-close-button { + @apply hover:bg-surface-200 focus-visible:outline-surface-600 + dark:hover:bg-surface-700 dark:focus-visible:outline-surface-300 +} + +.p-toast-message-contrast { + @apply bg-surface-900 border-surface-950 text-surface-50 + dark:bg-surface-0 dark:border-surface-100 dark:text-surface-950 + shadow-[0px_4px_8px_0px_rgba(0,0,0,0.04)] +} + +.p-toast-message-contrast .p-toast-detail { + @apply text-surface-0 dark:text-surface-950 +} + +.p-toast-message-contrast .p-toast-close-button { + @apply hover:bg-surface-800 focus-visible:outline-surface-50 + dark:hover:bg-surface-100 dark:focus-visible:outline-surface-950 +} + +.p-toast-top-center { + @apply -translate-x-1/2; +} + +.p-toast-bottom-center { + @apply -translate-x-1/2; +} + +.p-toast-center { + @apply min-w-[20vw] -translate-x-1/2 -translate-y-1/2 +} + +.p-toast-message-enter-from { + @apply opacity-0 translate-y-1/2 +} + +.p-toast-message-leave-from { + @apply max-h-[1000px] +} + +.p-toast .p-toast-message.p-toast-message-leave-to { + @apply max-h-0 opacity-0 mb-0 overflow-hidden +} + +.p-toast-message-enter-active { + @apply [transition:transform_0.3s,opacity_0.3s] +} + +.p-toast-message-leave-active { + @apply [transition:max-height_0.45s_cubic-bezier(0,1,0,1),opacity_0.3s,margin-bottom_0.3s] +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/togglebutton.css b/frontend/packages/kwai-ui/src/css/primevue/togglebutton.css new file mode 100644 index 000000000..0961add9b --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/togglebutton.css @@ -0,0 +1,63 @@ +.p-togglebutton { + @apply inline-flex items-center justify-center overflow-hidden relative cursor-pointer select-none + border border-surface-100 dark:border-surface-950 rounded-md + bg-surface-100 dark:bg-surface-950 + text-surface-500 dark:text-surface-400 text-base font-medium + px-4 py-2 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary + disabled:opacity-100 disabled:cursor-default + disabled:bg-surface-200 disabled:border-surface-200 disabled:text-surface-500 + disabled:dark:bg-surface-700 disabled:dark:border-surface-700 disabled:dark:text-surface-400 + transition-colors duration-300 + before:bg-transparent before:absolute before:start-1 before:top-1 before:rounded-md before:w-[calc(100%-0.5rem)] before:h-[calc(100%-0.5rem)] + before:transition-colors before:duration-200 +} + +.p-togglebutton-content { + @apply relative inline-flex items-center justify-center gap-2 +} + +.p-togglebutton-label, +.p-togglebutton-icon { + @apply relative transition-none +} + +.p-togglebutton.p-togglebutton-checked::before { + @apply bg-surface-0 dark:bg-surface-800 shadow-[0px_1px_2px_0px_rgba(0,0,0,0.02),0px_1px_2px_0px_rgba(0,0,0,0.04)] +} + +.p-togglebutton:not(:disabled):not(.p-togglebutton-checked):hover { + @apply bg-surface-100 dark:bg-surface-950 text-surface-700 dark:text-surface-300 +} + +.p-togglebutton.p-togglebutton-checked { + @apply bg-surface-100 dark:bg-surface-950 border-surface-100 dark:border-surface-950 text-surface-900 dark:text-surface-0 +} + +.p-togglebutton.p-invalid { + @apply border-red-400 dark:border-red-300 +} + +.p-togglebutton-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-togglebutton:not(:disabled):not(.p-togglebutton-checked):hover .p-togglebutton-icon { + @apply text-surface-700 dark:text-surface-300 +} + +.p-togglebutton.p-togglebutton-checked .p-togglebutton-icon { + @apply text-surface-900 dark:text-surface-0 +} + +.p-togglebutton:disabled .p-togglebutton-icon { + @apply text-surface-500 dark:text-surface-400 +} + +.p-togglebutton-sm { + @apply text-sm px-[0.75rem] py-[0.375rem] +} + +.p-togglebutton-lg { + @apply text-lg px-[1.25rem] py-[0.625rem] +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/toggleswitch.css b/frontend/packages/kwai-ui/src/css/primevue/toggleswitch.css new file mode 100644 index 000000000..ea4a9dc05 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/toggleswitch.css @@ -0,0 +1,66 @@ +.p-toggleswitch { + @apply inline-block w-10 h-6 +} + +.p-toggleswitch-input { + @apply cursor-pointer disabled:cursor-default appearance-none absolute top-0 start-0 w-full h-full m-0 p-0 opacity-0 z-10 rounded-[30px] +} + +.p-toggleswitch-slider { + @apply inline-block w-full h-full rounded-[30px] shadow-[0_1px_2px_0_rgba(18,18,23,0.05)] + bg-surface-300 dark:bg-surface-700 + border border-transparent + transition-colors duration-200 +} + +.p-toggleswitch-handle { + @apply absolute top-1/2 flex justify-center items-center + bg-surface-0 dark:bg-surface-400 + text-surface-500 dark:text-surface-900 + w-4 h-4 start-1 -mt-2 rounded-full + transition-[background,color,left] duration-200 +} + +.p-toggleswitch.p-toggleswitch-checked .p-toggleswitch-slider { + @apply bg-primary +} + +.p-toggleswitch.p-toggleswitch-checked .p-toggleswitch-handle { + @apply bg-surface-0 dark:bg-surface-900 text-primary start-5 +} + +.p-toggleswitch:not(.p-disabled):has(.p-toggleswitch-input:hover) .p-toggleswitch-slider { + @apply bg-surface-400 dark:bg-surface-600 +} + +.p-toggleswitch:not(.p-disabled):has(.p-toggleswitch-input:hover) .p-toggleswitch-handle { + @apply bg-surface-0 dark:bg-surface-300 text-surface-700 dark:text-surface-800 +} + +.p-toggleswitch:not(.p-disabled):has(.p-toggleswitch-input:hover).p-toggleswitch-checked .p-toggleswitch-slider { + @apply bg-primary-emphasis +} + +.p-toggleswitch:not(.p-disabled):has(.p-toggleswitch-input:hover).p-toggleswitch-checked .p-toggleswitch-handle { + @apply bg-surface-0 dark:bg-surface-900 text-primary-emphasis +} + +.p-toggleswitch:not(.p-disabled):has(.p-toggleswitch-input:focus-visible) .p-toggleswitch-slider { + @apply outline outline-1 outline-offset-2 outline-primary +} + +.p-toggleswitch.p-invalid > .p-toggleswitch-slider { + @apply border-red-400 dark:border-red-300 +} + +.p-toggleswitch.p-disabled { + @apply opacity-100 +} + +.p-toggleswitch.p-disabled .p-toggleswitch-slider { + @apply bg-surface-200 dark:bg-surface-600 +} + +.p-toggleswitch.p-disabled .p-toggleswitch-handle { + @apply bg-surface-700 dark:bg-surface-900 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/toolbar.css b/frontend/packages/kwai-ui/src/css/primevue/toolbar.css new file mode 100644 index 000000000..8c46bd166 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/toolbar.css @@ -0,0 +1,12 @@ +.p-toolbar { + @apply flex items-center justify-between flex-wrap p-3 gap-2 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 + border border-surface-200 dark:border-surface-700 rounded-md +} + +.p-toolbar-start, +.p-toolbar-center, +.p-toolbar-end { + @apply flex items-center +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/tooltip.css b/frontend/packages/kwai-ui/src/css/primevue/tooltip.css new file mode 100644 index 000000000..a7aac7224 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/tooltip.css @@ -0,0 +1,38 @@ +.p-tooltip { + @apply absolute hidden max-w-48 +} + +.p-tooltip-right, +.p-tooltip-left { + @apply py-0 px-1 +} + +.p-tooltip-top, +.p-tooltip-bottom { + @apply py-1 px-0 +} + +.p-tooltip-text { + @apply whitespace-pre-line break-words bg-surface-700 text-surface-0 py-2 px-3 + rounded-md shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + +.p-tooltip-arrow { + @apply absolute w-0 h-0 border-solid border-transparent +} + +.p-tooltip-right .p-tooltip-arrow { + @apply -mt-1 border-[.25rem] border-s-0 border-e-surface-700 rtl:rotate-180 +} + +.p-tooltip-left .p-tooltip-arrow { + @apply -mt-1 border-[.25rem] border-e-0 border-s-surface-700 rtl:rotate-180 +} + +.p-tooltip-top .p-tooltip-arrow { + @apply -ms-1 border-[.25rem] border-b-0 border-t-surface-700 +} + +.p-tooltip-bottom .p-tooltip-arrow { + @apply -ms-1 border-[.25rem] border-t-0 border-b-surface-700 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/tree.css b/frontend/packages/kwai-ui/src/css/primevue/tree.css new file mode 100644 index 000000000..933f1e196 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/tree.css @@ -0,0 +1,103 @@ +.p-tree { + @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 p-4 +} + +.p-tree-root-children, +.p-tree-node-children { + @apply flex flex-col list-none m-0 gap-[2px] +} + +.p-tree-root-children { + @apply pt-[2px] pb-0 px-0 +} + +.p-tree-node-children { + @apply pt-[2px] pe-0 pb-0 ps-4 +} + +.p-tree-node { + @apply p-0 outline-none +} + +.p-tree-node-content { + @apply rounded-md px-2 py-1 flex items-center text-surface-700 dark:text-surface-0 gap-1 transition-colors duration-200 +} + +.p-tree-node:focus-visible > .p-tree-node-content { + @apply outline outline-1 outline-offset-2 outline-primary +} + +.p-tree-node-content.p-tree-node-selectable:not(.p-tree-node-selected):hover { + @apply bg-surface-100 text-surface-700 dark:bg-surface-800 dark:text-surface-0 +} + +.p-tree-node-content.p-tree-node-selectable:not(.p-tree-node-selected):hover .p-tree-node-icon { + @apply text-surface-600 dark:text-surface-300 +} + +.p-tree-node-content.p-tree-node-selected { + @apply bg-highlight +} + +.p-tree-node-content.p-tree-node-selected .p-tree-node-toggle-button { + @apply text-inherit +} + +.p-tree-node-toggle-button { + @apply cursor-pointer select-none inline-flex justify-center rounded-full items-center overflow-hidden relative flex-shrink-0 + w-7 h-7 p-0 transition-colors duration-200 border-none + bg-transparent enabled:hover:bg-surface-100 dark:enabled:hover:bg-surface-800 + text-surface-500 dark:text-surface-400 enabled:hover:text-surface-600 dark:enabled:hover:text-surface-300 +} + +.p-tree-node-content.p-tree-node-selected .p-tree-node-toggle-button:hover { + @apply bg-surface-0 dark:bg-surface-900 text-primary +} + +.p-tree-root { + @apply overflow-auto +} + +.p-tree-node-selectable { + @apply cursor-pointer select-none +} + +.p-tree-node-leaf > .p-tree-node-content .p-tree-node-toggle-button { + @apply invisible +} + +.p-tree-node-icon { + @apply text-surface-500 dark:text-surface-400 transition-colors duration-200 +} + +.p-tree-node-content.p-tree-node-selected .p-tree-node-icon { + @apply text-primary +} + +.p-tree-filter { + @apply mb-2 +} + +.p-tree-filter-input { + @apply w-full +} + +.p-tree-loading { + @apply relative h-full +} + +.p-tree-loading-icon { + @apply text-[2rem] h-8 w-8 +} + +.p-tree .p-tree-mask { + @apply absolute z-10 flex items-center justify-center +} + +.p-tree-flex-scrollable { + @apply flex flex-1 h-full flex-col +} + +.p-tree-flex-scrollable .p-tree-root { + @apply flex-1 +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/treeselect.css b/frontend/packages/kwai-ui/src/css/primevue/treeselect.css new file mode 100644 index 000000000..1fd487668 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/treeselect.css @@ -0,0 +1,112 @@ +@import './chip'; +@import './tree'; + +.p-treeselect { + @apply inline-flex cursor-pointer relative select-none rounded-md + bg-surface-0 dark:bg-surface-950 + border border-surface-300 dark:border-surface-700 + shadow-[0_1px_2px_0_rgba(18,18,23,0.05)] + transition-colors duration-200 +} + +.p-treeselect:not(.p-disabled):hover { + @apply border-surface-400 dark:border-surface-600 +} + +.p-treeselect:not(.p-disabled).p-focus { + @apply border-primary +} + +.p-treeselect.p-variant-filled { + @apply bg-surface-50 dark:bg-surface-800 +} + +.p-treeselect.p-invalid { + @apply border-red-400 dark:border-red-300 +} + +.p-treeselect.p-disabled { + @apply bg-surface-200 text-surface-500 dark:bg-surface-700 dark:text-surface-400 opacity-100 cursor-default +} + +.p-treeselect-dropdown { + @apply flex items-center justify-center shrink-0 bg-transparent + text-surface-500 dark:text-surface-400 w-10 rounded-e-md +} + +.p-treeselect-label-container { + @apply overflow-hidden flex-auto +} + +.p-treeselect-label { + @apply flex items-center gap-1 whitespace-nowrap text-ellipsis px-3 py-2 text-surface-700 dark:text-surface-0 +} + +.p-treeselect-label.p-placeholder { + @apply text-surface-500 dark:text-surface-400 +} + +.p-treeselect.p-disabled .p-treeselect-label { + @apply text-surface-500 dark:text-surface-400 +} + +.p-treeselect-label-empty { + @apply overflow-hidden invisible +} + +.p-treeselect .p-treeselect-overlay { + @apply min-w-full +} + +.p-treeselect-overlay { + @apply absolute top-0 left-0 rounded-md + bg-surface-0 dark:bg-surface-900 + border border-surface-200 dark:border-surface-700 + text-surface-700 dark:text-surface-0 + shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-2px_rgba(0,0,0,0.1)] +} + + +.p-treeselect-tree-container { + @apply overflow-auto +} + +.p-treeselect-empty-message { + @apply px-3 py-2 +} + +.p-treeselect-fluid { + @apply flex +} + +.p-treeselect-overlay .p-tree { + @apply p-1 +} + +.p-treeselect-overlay .p-tree-loading { + @apply min-h-12 +} + +.p-treeselect-label .p-chip { + @apply pt-1 pb-1 rounded-sm +} + +.p-treeselect-label:has(.p-chip) { + @apply py-1 px-1 +} + +.p-treeselect-sm .p-treeselect-label { + @apply text-sm px-[0.625rem] py-[0.375rem] +} + +.p-treeselect-sm .p-treeselect-dropdown .p-icon { + @apply text-sm w-[0.875rem] h-[0.875rem] +} + +.p-treeselect-lg .p-treeselect-label { + @apply text-lg px-[0.875rem] py-[0.625rem] +} + +.p-treeselect-lg .p-treeselect-dropdown .p-icon { + @apply text-lg w-[1.125rem] h-[1.125rem] +} diff --git a/frontend/packages/kwai-ui/src/css/primevue/treetable.css b/frontend/packages/kwai-ui/src/css/primevue/treetable.css new file mode 100644 index 000000000..a9c014240 --- /dev/null +++ b/frontend/packages/kwai-ui/src/css/primevue/treetable.css @@ -0,0 +1,300 @@ +@import './paginator'; + +.p-treetable { + @apply relative +} + +.p-treetable-table { + @apply border-spacing-0 w-full +} + +.p-treetable-scrollable > .p-treetable-table-container { + @apply relative +} + +.p-treetable-scrollable-table > .p-treetable-thead { + @apply top-0 z-10 +} + +.p-treetable-scrollable-table > .p-treetable-frozen-tbody { + @apply sticky z-10 +} + +.p-treetable-scrollable-table>.p-treetable-tfoot { + @apply bottom-0 z-10 +} + +.p-treetable-scrollable .p-treetable-frozen-column { + @apply sticky bg-surface-0 dark:bg-surface-900 +} + +.p-treetable-scrollable th.p-treetable-frozen-column { + @apply z-10 +} + +.p-treetable-scrollable > .p-treetable-table-container > .p-treetable-table > .p-treetable-thead { + @apply bg-surface-0 dark:bg-surface-900 +} + +.p-treetable-scrollable > .p-treetable-table-container > .p-treetable-table > .p-treetable-tfoot { + @apply bg-surface-0 dark:bg-surface-900 +} + +.p-treetable-flex-scrollable { + @apply flex flex-col h-full +} + +.p-treetable-flex-scrollable > .p-treetable-table-container { + @apply flex flex-col flex-1 h-full +} + +.p-treetable-scrollable-table > .p-treetable-tbody > .p-treetable-row-group-header { + @apply sticky z-10 +} + +.p-treetable-resizable-table > .p-treetable-thead > tr > th, +.p-treetable-resizable-table > .p-treetable-tfoot > tr > td, +.p-treetable-resizable-table > .p-treetable-tbody > tr > td { + @apply overflow-hidden whitespace-nowrap +} + +.p-treetable-resizable-table > .p-treetable-thead > tr > th.p-treetable-resizable-column:not(.p-treetable-frozen-column) { + @apply bg-clip-padding relative +} + +.p-treetable-resizable-table-fit > .p-treetable-thead > tr > th.p-treetable-resizable-column:last-child .p-treetable-column-resizer { + @apply hidden +} + +.p-treetable-column-resizer { + @apply block absolute top-0 end-0 m-0 w-2 h-full p-0 cursor-col-resize border border-transparent +} + +.p-treetable-column-header-content { + @apply flex items-center gap-2 +} + +.p-treetable-column-resize-indicator { + @apply w-px absolute z-10 hidden bg-primary +} + +.p-treetable-mask { + @apply absolute flex items-center justify-center z-20 +} + +.p-treetable-paginator-top { + @apply border-b border-surface-200 dark:border-surface-700 +} + +.p-treetable-paginator-bottom { + @apply border-t border-surface-200 dark:border-surface-700 +} + +.p-treetable-header { + @apply py-3 px-4 border-b border-surface-200 dark:border-surface-700 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 +} + +.p-treetable-footer { + @apply py-3 px-4 border-b border-surface-200 dark:border-surface-700 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 +} + +.p-treetable-header-cell { + @apply py-3 px-4 font-normal text-start transition-colors duration-200 + border-b border-surface-200 dark:border-surface-700 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 +} + +.p-treetable-column-title { + @apply font-semibold +} + +.p-treetable-tbody > tr { + @apply bg-surface-0 dark:bg-surface-900 text-surface-700 dark:text-surface-0 transition-colors duration-200 +} + +.p-treetable-tbody > tr > td { + @apply text-start py-3 px-4 border-b border-surface-200 dark:border-surface-800 +} + +.p-treetable-hoverable .p-treetable-tbody > tr:not(.p-treetable-row-selected):hover { + @apply bg-surface-100 text-surface-800 dark:bg-surface-800 dark:text-surface-0 +} + +.p-treetable-tbody > tr.p-treetable-row-selected { + @apply bg-highlight +} + +.p-treetable-tbody > tr:has(+ .p-treetable-row-selected) > td { + @apply border-b-primary-100 dark:border-b-primary-900 +} + +.p-treetable-tbody > tr.p-treetable-row-selected > td { + @apply border-b-primary-100 dark:border-b-primary-900 +} + +.p-treetable-tbody > tr:focus-visible, +.p-treetable-tbody > tr.p-treetable-contextmenu-row-selected { + @apply outline outline-1 -outline-offset-1 outline-primary +} + +.p-treetable-tfoot > tr > td { + @apply text-start py-3 px-4 border-b border-surface-200 dark:border-surface-800 + bg-surface-0 dark:bg-surface-900 + text-surface-700 dark:text-surface-0 +} + +.p-treetable-column-footer { + @apply font-semibold +} + +.p-treetable-sortable-column { + @apply cursor-pointer select-none focus-visible:outline focus-visible:outline-1 focus-visible:-outline-offset-1 focus-visible:outline-primary +} + +.p-treetable-column-title, +.p-treetable-sort-icon, +.p-treetable-sort-badge { + @apply align-middle +} + +.p-treetable-sort-icon { + @apply text-surface-500 dark:text-surface-400 transition-colors duration-200 +} + +.p-treetable-sortable-column:not(.p-treetable-column-sorted):hover { + @apply bg-surface-100 text-surface-800 dark:bg-surface-800 dark:text-surface-0 +} + +.p-treetable-sortable-column:not(.p-treetable-column-sorted):hover .p-treetable-sort-icon { + @apply text-surface-600 dark:text-surface-300 +} + +.p-treetable-column-sorted { + @apply bg-highlight +} + +.p-treetable-column-sorted .p-treetable-sort-icon { + @apply bg-highlight +} + +.p-treetable-hoverable .p-treetable-selectable-row { + @apply cursor-pointer +} + +.p-treetable-loading-icon { + @apply text-[2rem] w-8 h-8 +} + +.p-treetable-gridlines .p-treetable-header { + @apply border-t border-x +} + +.p-treetable-gridlines .p-treetable-footer { + @apply border-b border-x +} + +.p-treetable-gridlines .p-treetable-paginator-top { + @apply border-t border-x +} + +.p-treetable-gridlines .p-treetable-paginator-bottom { + @apply border-b border-x +} + +.p-treetable-gridlines .p-treetable-thead > tr > th { + @apply border-t border-x last:border +} + +.p-treetable-gridlines .p-treetable-tbody > tr > td { + @apply border-t border-s last:border-r +} + +.p-treetable-gridlines .p-treetable-tbody > tr:last-child > td { + @apply border-y border-s last:border +} + +.p-treetable-gridlines .p-treetable-tfoot > tr > td { + @apply border-y border-s last:border +} + +.p-treetable.p-treetable-gridlines .p-treetable-thead + .p-treetable-tfoot > tr > td { + @apply border-b border-s last:border-r +} + +.p-treetable.p-treetable-gridlines:has(.p-treetable-thead):has(.p-treetable-tbody) .p-treetable-tbody > tr > td { + @apply border-b border-s last:border-r +} + +.p-treetable.p-treetable-gridlines:has(.p-treetable-tbody):has(.p-treetable-tfoot) .p-treetable-tbody > tr:last-child > td { + @apply border-x +} + +.p-treetable.p-treetable-sm .p-treetable-header { + @apply py-1 px-2 +} + +.p-treetable.p-treetable-sm .p-treetable-thead > tr > th { + @apply py-1 px-2 +} + +.p-treetable.p-treetable-sm .p-treetable-tbody > tr > td { + @apply py-1 px-2 +} + +.p-treetable.p-treetable-sm .p-treetable-tfoot > tr > td { + @apply py-1 px-2 +} + +.p-treetable.p-treetable-sm .p-treetable-footer { + @apply py-1 px-2 +} + +.p-treetable.p-treetable-lg .p-treetable-header { + @apply py-4 px-5 +} + +.p-treetable.p-treetable-lg .p-treetable-thead > tr > th { + @apply py-4 px-5 +} + +.p-treetable.p-treetable-lg .p-treetable-tbody>tr>td { + @apply py-4 px-5 +} + +.p-treetable.p-treetable-lg .p-treetable-tfoot>tr>td { + @apply py-4 px-5 +} + +.p-treetable.p-treetable-lg .p-treetable-footer { + @apply py-4 px-5 +} + +.p-treetable-body-cell-content { + @apply flex items-center gap-2 +} + +.p-treetable-tbody > tr.p-treetable-row-selected .p-treetable-node-toggle-button { + @apply text-inherit +} + +.p-treetable-node-toggle-button { + @apply inline-flex items-center justify-center overflow-hidden relative select-none + transition-colors duration-200 w-7 h-7 rounded-full border-none bg-transparent cursor-pointer + enabled:hover:bg-surface-100 dark:enabled:hover:bg-surface-900 + text-surface-500 dark:text-surface-400 enabled:hover:text-surface-700 dark:enabled:hover:text-surface-0 + focus-visible:outline focus-visible:outline-1 focus-visible:outline-offset-2 focus-visible:outline-primary + +} + +.p-treetable-tbody > tr.p-treetable-row-selected .p-treetable-node-toggle-button:hover { + @apply bg-surface-0 dark:bg-surface-900 text-primary +} + +.p-treetable-node-toggle-icon:dir(rtl) { + @apply rotate-180 +} diff --git a/frontend/packages/kwai-ui/src/form/Button.vue b/frontend/packages/kwai-ui/src/form/Button.vue deleted file mode 100644 index 41450a016..000000000 --- a/frontend/packages/kwai-ui/src/form/Button.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/frontend/packages/kwai-ui/src/form/KwaiButton.vue b/frontend/packages/kwai-ui/src/form/KwaiButton.vue index fab4f1fb5..4057257be 100644 --- a/frontend/packages/kwai-ui/src/form/KwaiButton.vue +++ b/frontend/packages/kwai-ui/src/form/KwaiButton.vue @@ -2,46 +2,45 @@ diff --git a/frontend/packages/kwai-ui/src/form/KwaiButtonGroup.vue b/frontend/packages/kwai-ui/src/form/KwaiButtonGroup.vue index e9a19e4a7..4a1496721 100644 --- a/frontend/packages/kwai-ui/src/form/KwaiButtonGroup.vue +++ b/frontend/packages/kwai-ui/src/form/KwaiButtonGroup.vue @@ -1,6 +1,10 @@ + + diff --git a/frontend/packages/kwai-ui/src/form/KwaiCheckbox.vue b/frontend/packages/kwai-ui/src/form/KwaiCheckbox.vue index 1dd0c869e..6037df9f2 100644 --- a/frontend/packages/kwai-ui/src/form/KwaiCheckbox.vue +++ b/frontend/packages/kwai-ui/src/form/KwaiCheckbox.vue @@ -1,25 +1,34 @@ diff --git a/frontend/packages/kwai-ui/src/form/KwaiCheckboxField.vue b/frontend/packages/kwai-ui/src/form/KwaiCheckboxField.vue new file mode 100644 index 000000000..a7dcae4ad --- /dev/null +++ b/frontend/packages/kwai-ui/src/form/KwaiCheckboxField.vue @@ -0,0 +1,49 @@ + + + diff --git a/frontend/packages/kwai-ui/src/form/DatePicker.vue b/frontend/packages/kwai-ui/src/form/KwaiDatePicker.vue similarity index 61% rename from frontend/packages/kwai-ui/src/form/DatePicker.vue rename to frontend/packages/kwai-ui/src/form/KwaiDatePicker.vue index 2a3d6d8bc..77fc21e67 100644 --- a/frontend/packages/kwai-ui/src/form/DatePicker.vue +++ b/frontend/packages/kwai-ui/src/form/KwaiDatePicker.vue @@ -2,34 +2,31 @@ import { toRef, useSlots } from 'vue'; import { useField } from 'vee-validate'; import RequiredIcon from '../icons/RequiredIcon.vue'; -import VueDatePicker from '@vuepic/vue-datepicker'; -import '@vuepic/vue-datepicker/dist/main.css'; -import { createFromDate } from '@kwai/date'; +import DatePicker from 'primevue/datepicker'; -const props = defineProps<{ +interface Props { name: string, - id?: string, + id?: string | null, placeholder?: string format?: string time?: boolean required?: boolean -}>(); +} + +const props = withDefaults( + defineProps(), + { + id: null, + placeholder: '', + format: 'dd-mm-yy', + time: false, + required: false, + } +); const slots = useSlots(); const nameRef = toRef(props, 'name'); const { value, errorMessage } = useField(nameRef); - -const format = (date: Date | null) : string => { - if (date) { - const formatString = props.format ?? (props.time ? 'L LTS' : 'L'); - try { - return createFromDate(date).format(formatString); - } catch (e) { - console.log(e); - } - } - return ''; -};