diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 04a7192419..1c2bbe2dae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,11 +9,11 @@ jobs: run: working-directory: ./backend steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.8 - uses: actions/setup-python@v2 + - uses: actions/checkout@v4 + - name: Set up Python 3.10 + uses: actions/setup-python@v5 with: - python-version: 3.8 + python-version: '3.10' - name: Install dependencies run: | python -m pip install --upgrade pip @@ -45,10 +45,10 @@ jobs: run: working-directory: ./frontend steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: "16" + node-version: '18' - name: Install Yarn run: npm install -g yarn - name: Install npm modules @@ -65,6 +65,6 @@ jobs: run: working-directory: ./docker steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: hadolint run: hadolint ./Dockerfile* diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d629a42afd..deeed48378 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -3,7 +3,7 @@ # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. -name: "CodeQL" +name: 'CodeQL' on: push: @@ -29,43 +29,43 @@ jobs: # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection steps: - - name: Checkout repository - uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 + - name: Checkout repository + uses: actions/checkout@v4 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language - #- run: | - # make bootstrap - # make release + #- run: | + # make bootstrap + # make release - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/mkdocs-deployment.yml b/.github/workflows/mkdocs-deployment.yml index 38fe8234c9..da8bce7132 100644 --- a/.github/workflows/mkdocs-deployment.yml +++ b/.github/workflows/mkdocs-deployment.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout main - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Deploy docs uses: mhausenblas/mkdocs-deploy-gh-pages@1.16 env: diff --git a/.github/workflows/publish-image.yml b/.github/workflows/publish-image.yml index f989c5541c..3563c85c3e 100644 --- a/.github/workflows/publish-image.yml +++ b/.github/workflows/publish-image.yml @@ -4,8 +4,6 @@ on: schedule: - cron: '0 10 * * *' # everyday at 10am push: - branches: - - master tags: - 'v*.*.*' @@ -13,39 +11,58 @@ jobs: docker: runs-on: ubuntu-latest steps: - - - name: Checkout - uses: actions/checkout@v2 - - - name: Docker meta + - name: Checkout + uses: actions/checkout@v4 + + - name: Docker meta id: docker_meta uses: crazy-max/ghaction-docker-meta@v1 with: images: doccano/doccano - tag-sha: true tag-semver: | {{version}} {{major}}.{{minor}} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to DockerHub if: github.event_name != 'pull_request' - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push + + - name: Build and push id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v3 with: context: . + platforms: linux/amd64,linux/arm64 file: ./docker/Dockerfile push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.docker_meta.outputs.tags }} labels: ${{ steps.docker_meta.outputs.labels }} + + - name: Build a backend image and push + uses: docker/build-push-action@v3 + with: + context: . + platforms: linux/amd64,linux/arm64 + file: ./docker/Dockerfile.prod + push: ${{ github.event_name != 'pull_request' }} + tags: doccano/doccano:backend + labels: ${{ steps.docker_meta.outputs.labels }} + + - name: Build a frontend image and push + uses: docker/build-push-action@v3 + with: + context: . + platforms: linux/amd64,linux/arm64 + file: ./docker/Dockerfile.nginx + push: ${{ github.event_name != 'pull_request' }} + tags: doccano/doccano:frontend + labels: ${{ steps.docker_meta.outputs.labels }} diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml index c67f2e95c4..4e37362f84 100644 --- a/.github/workflows/pypi-publish.yml +++ b/.github/workflows/pypi-publish.yml @@ -7,47 +7,50 @@ on: jobs: deploy: runs-on: ubuntu-latest - + environment: + name: pypi + url: https://pypi.org/p/doccano + permissions: + id-token: write steps: - - uses: actions/checkout@v2 - - name: Preparation - run: | - mkdir backend/client - - name: Fix up git URLs - run: echo -e '[url "https://github.com/"]\n insteadOf = "git@github.com:"' >> ~/.gitconfig - - name: Use Node.js - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - name: Build with Node.js - run: | - yarn install - yarn build - cp -r dist ../backend/client/ - working-directory: ./frontend - env: - PUBLIC_PATH: "/static/_nuxt/" - - name: Setup Python 3.8 - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install poetry poetry-dynamic-versioning - poetry install - working-directory: ./backend - - name: collectstatic - run: | - poetry run task collectstatic - working-directory: ./backend - - name: Build a binary wheel and a source tarball - run: | - sed -e "s/, from = \"..\"//g" backend/pyproject.toml > pyproject.toml - poetry build - - name: Publish a Python distribution to PyPI - uses: pypa/gh-action-pypi-publish@master - with: - user: ${{ secrets.PYPI_USERNAME }} - password: ${{ secrets.PYPI_PASSWORD }} - packages_dir: ./dist/ + - uses: actions/checkout@v4 + - name: Preparation + run: | + mkdir backend/client + - name: Fix up git URLs + run: echo -e '[url "https://github.com/"]\n insteadOf = "git@github.com:"' >> ~/.gitconfig + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: '18.x' + - name: Build with Node.js + run: | + yarn install + yarn build + cp -r dist ../backend/client/ + working-directory: ./frontend + env: + PUBLIC_PATH: '/static/_nuxt/' + - name: Setup Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install poetry poetry-dynamic-versioning + poetry install + working-directory: ./backend + - name: collectstatic + run: | + poetry run task collectstatic + working-directory: ./backend + - name: Build a binary wheel and a source tarball + run: | + sed -e "s/, from = \"..\"//g" backend/pyproject.toml > pyproject.toml + poetry build + - name: Publish a Python distribution to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.TEST_PYPI_API_TOKEN }} + packages_dir: ./dist/ diff --git a/.github/workflows/test-installation.yml b/.github/workflows/test-installation.yml new file mode 100644 index 0000000000..76e36e2335 --- /dev/null +++ b/.github/workflows/test-installation.yml @@ -0,0 +1,32 @@ +name: Test installation and doccano commands + +on: + schedule: + - cron: '15 22 * * *' + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] + python-version: ['3.10', '3.11', '3.12'] + steps: + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Enabling JSON1 extension on SQLite + if: ${{ startsWith(matrix.os, 'windows') && matrix.python-version == '3.8' }} + shell: bash + run: | + export VERSION=`python -V | cut -f2 -d " "` + curl -LO https://www.sqlite.org/2022/sqlite-dll-win64-x64-3390300.zip + unzip sqlite-dll-win64-x64-3390300.zip + mv sqlite3.dll /c/hostedtoolcache/windows/Python/$VERSION/x64/DLLs/ + - name: Test installation + run: pip install doccano + - name: Test doccano init command + run: doccano init + - name: Test doccano createuser command + run: doccano createuser --username admin --password pass diff --git a/LICENSE b/LICENSE index 12d0eb425b..d9a2c1a8f8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 TIS inc. +Copyright (c) 2018 Hiroki Nakayama Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index a2befc8f24..30058019cf 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,17 @@ [![Codacy Badge](https://app.codacy.com/project/badge/Grade/35ac8625a2bc4eddbff23dbc61bc6abb)](https://www.codacy.com/gh/doccano/doccano/dashboard?utm_source=github.com&utm_medium=referral&utm_content=doccano/doccano&utm_campaign=Badge_Grade) [![doccano CI](https://github.com/doccano/doccano/actions/workflows/ci.yml/badge.svg)](https://github.com/doccano/doccano/actions/workflows/ci.yml) -doccano is an open source text annotation tool for humans. It provides annotation features for text classification, sequence labeling and sequence to sequence tasks. So, you can create labeled data for sentiment analysis, named entity recognition, text summarization and so on. Just create a project, upload data and start annotating. You can build a dataset in hours. +doccano is an open-source text annotation tool for humans. It provides annotation features for text classification, sequence labeling, and sequence to sequence tasks. You can create labeled data for sentiment analysis, named entity recognition, text summarization, and so on. Just create a project, upload data, and start annotating. You can build a dataset in hours. ## Demo -You can try the [annotation demo](http://doccano.herokuapp.com). +Try the [annotation demo](http://doccano.herokuapp.com). ![Demo image](https://raw.githubusercontent.com/doccano/doccano/master/docs/images/demo/demo.gif) ## Documentation -Read the documentation at the . +Read the documentation at . ## Features @@ -30,7 +30,7 @@ Read the documentation at the . ## Usage -Three options to run doccano: +There are three options to run doccano: - pip (Python 3.8+) - Docker @@ -38,7 +38,7 @@ Three options to run doccano: ### pip -To install doccano, simply run: +To install doccano, run: ```bash pip install doccano @@ -49,7 +49,9 @@ By default, SQLite 3 is used for the default database. If you want to use Postgr ```bash pip install 'doccano[postgresql]' ``` -and set `DATABASE_URL` environment variable according to your PostgreSQL credentials: + +and set the `DATABASE_URL` environment variable according to your PostgreSQL credentials: + ```bash DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable" ``` @@ -65,7 +67,7 @@ doccano createuser --username admin --password pass doccano webserver --port 8000 ``` -In another terminal, run the following command: +In another terminal, run the command: ```bash # Start the task queue to handle file upload/download. @@ -96,12 +98,17 @@ docker container start doccano Go to . -To stop the container, run `docker container stop doccano -t 5`. -All data created in the container will persist across restarts. +To stop the container, run `docker container stop doccano -t 5`. All data created in the container will persist across restarts. + +If you want to use the latest features, specify the `nightly` tag: + +```bash +docker pull doccano/doccano:nightly +``` ### Docker Compose -You need to install Git and to clone the repository: +You need to install Git and clone the repository: ```bash git clone https://github.com/doccano/doccano.git @@ -182,4 +189,4 @@ Here are some tips might be helpful. [How to Contribute to Doccano Project](http ## Contact -For help and feedback, please feel free to contact [the author](https://github.com/Hironsan). +For help and feedback, feel free to contact [the author](https://github.com/Hironsan). diff --git a/app.json b/app.json index fb5933a28e..e175958254 100644 --- a/app.json +++ b/app.json @@ -37,7 +37,7 @@ }, "addons": [ { - "plan": "heroku-postgresql:hobby-dev" + "plan": "heroku-postgresql:mini" } ] } diff --git a/backend/api/management/commands/create_admin.py b/backend/api/management/commands/create_admin.py index c845e1929c..fcd67bac1e 100644 --- a/backend/api/management/commands/create_admin.py +++ b/backend/api/management/commands/create_admin.py @@ -13,9 +13,17 @@ def handle(self, *args, **options): password = options.get("password") username = options.get("username") - if password and not username: + if not username: + self.stderr.write("Error: Blank username isn't allowed.") raise CommandError("--username is required if specifying --password") + if not password: + self.stderr.write("Error: Blank password isn't allowed.") + raise CommandError("--password is required") + + if password == "password": + self.stdout.write(self.style.WARNING("Warning: You should change the default password.")) + try: super().handle(*args, **options) except Exception as err: @@ -24,10 +32,10 @@ def handle(self, *args, **options): else: raise - if password: - database = options.get("database") - db = self.UserModel._default_manager.db_manager(database) - user = db.get(username=username) - user.set_password(password) - self.stderr.write(f"Setting password for User {username}.") - user.save() + database = options.get("database") + db = self.UserModel._default_manager.db_manager(database) + user = db.get(username=username) + user.set_password(password) + message = f"Setting password for User {username}." + self.stdout.write(self.style.SUCCESS(message)) + user.save() diff --git a/backend/api/tests/test_commands.py b/backend/api/tests/test_commands.py new file mode 100644 index 0000000000..ead584a9e2 --- /dev/null +++ b/backend/api/tests/test_commands.py @@ -0,0 +1,72 @@ +from unittest.mock import MagicMock + +from django.contrib.auth import get_user_model +from django.core.management import CommandError +from django.test import TestCase + +from api.management.commands.create_admin import Command + + +class TestCreateAdminCommand(TestCase): + def test_can_create_user(self): + mock_out = MagicMock() + command = Command(stdout=mock_out) + command.handle( + username="user", + password="whoami", + email="example@doccano.com", + database="default", + interactive=False, + verbosity=0, + ) + self.assertEqual(get_user_model().objects.count(), 1) + mock_out.write.assert_called_once_with("Setting password for User user.\n") + + def test_raise_error_if_username_is_not_given(self): + mock_err = MagicMock() + command = Command(stderr=mock_err) + with self.assertRaises(CommandError): + command.handle( + password="whoami", email="example@doccano.com", database="default", interactive=False, verbosity=0 + ) + mock_err.write.assert_called_once_with("Error: Blank username isn't allowed.\n") + + def test_raise_error_if_password_is_not_given(self): + mock_err = MagicMock() + command = Command(stderr=mock_err) + with self.assertRaises(CommandError): + command.handle( + username="user", email="example@doccano.com", database="default", interactive=False, verbosity=0 + ) + mock_err.write.assert_called_once_with("Error: Blank password isn't allowed.\n") + + def test_warn_default_password(self): + mock_out = MagicMock() + command = Command(stdout=mock_out) + command.handle( + username="user", + password="password", + email="example@doccano.com", + database="default", + interactive=False, + verbosity=0, + ) + self.assertEqual(get_user_model().objects.count(), 1) + self.assertEqual(mock_out.write.call_count, 2) + mock_out.write.assert_any_call("Warning: You should change the default password.\n") + mock_out.write.assert_any_call("Setting password for User user.\n") + + def test_warn_duplicate_username(self): + get_user_model().objects.create(username="admin", password="pass") + mock_err = MagicMock() + command = Command(stderr=mock_err) + command.handle( + username="admin", + password="whoami", + email="example@doccano.com", + database="default", + interactive=False, + verbosity=0, + ) + self.assertEqual(get_user_model().objects.count(), 1) + mock_err.write.assert_called_once_with("User admin already exists.\n") diff --git a/backend/api/tests/utils.py b/backend/api/tests/utils.py index 1073ef0e5b..a52fd0e24b 100644 --- a/backend/api/tests/utils.py +++ b/backend/api/tests/utils.py @@ -29,8 +29,11 @@ def assert_update(self, user=None, expected=status.HTTP_403_FORBIDDEN): self.assertEqual(response.status_code, expected) return response - def assert_delete(self, user=None, expected=status.HTTP_403_FORBIDDEN): + def assert_delete(self, user=None, expected=status.HTTP_403_FORBIDDEN, data=None): if user: self.client.force_login(user) - response = self.client.delete(self.url) + + if data is None: + data = {} + response = self.client.delete(self.url, data=data) self.assertEqual(response.status_code, expected) diff --git a/backend/api/urls.py b/backend/api/urls.py index ee260b1b74..ba5595afc3 100644 --- a/backend/api/urls.py +++ b/backend/api/urls.py @@ -3,5 +3,5 @@ from .views import TaskStatus urlpatterns = [ - path(route="tasks/status/", view=TaskStatus.as_view(), name="task_status"), + path(route="tasks/status/", view=TaskStatus.as_view(), name="task_status"), ] diff --git a/backend/auto_labeling/exceptions.py b/backend/auto_labeling/exceptions.py index 8b94890b6f..a6368e4c0c 100644 --- a/backend/auto_labeling/exceptions.py +++ b/backend/auto_labeling/exceptions.py @@ -24,3 +24,7 @@ class SampleDataException(ValidationError): class TemplateMappingError(ValidationError): default_detail = "The response cannot be mapped. You might need to change the template." + + +class ResponseJSONDecodeError(ValidationError): + default_detail = "The response cannot be decoded." "Please try to return the response in dictionary or list format." diff --git a/backend/auto_labeling/migrations/0003_fill_task_type.py b/backend/auto_labeling/migrations/0003_fill_task_type.py index 3fbfa1eb8a..4bb3666516 100644 --- a/backend/auto_labeling/migrations/0003_fill_task_type.py +++ b/backend/auto_labeling/migrations/0003_fill_task_type.py @@ -1,17 +1,17 @@ from django.db import migrations -from projects.models import DOCUMENT_CLASSIFICATION, SEQUENCE_LABELING, SEQ2SEQ, SPEECH2TEXT, IMAGE_CLASSIFICATION +from projects.models import ProjectType def fill_task_type(apps, schema_editor): AutoLabelingConfig = apps.get_model("auto_labeling", "AutoLabelingConfig") for config in AutoLabelingConfig.objects.all(): project = config.project - if project.project_type in [DOCUMENT_CLASSIFICATION, IMAGE_CLASSIFICATION]: + if project.project_type in [ProjectType.DOCUMENT_CLASSIFICATION, ProjectType.IMAGE_CLASSIFICATION]: config.task_type = "Category" - elif project.project_type in [SEQ2SEQ, SPEECH2TEXT]: + elif project.project_type in [ProjectType.SEQ2SEQ, ProjectType.SPEECH2TEXT]: config.task_type = "Text" - elif project.project_type in [SEQUENCE_LABELING]: + elif project.project_type in [ProjectType.SEQUENCE_LABELING]: config.task_type = "Span" else: config.task_type = "Category" diff --git a/backend/auto_labeling/tests/test_views.py b/backend/auto_labeling/tests/test_views.py index cedcccdfd1..8518a599f4 100644 --- a/backend/auto_labeling/tests/test_views.py +++ b/backend/auto_labeling/tests/test_views.py @@ -11,7 +11,7 @@ from auto_labeling.pipeline.labels import Categories, Spans, Texts from examples.tests.utils import make_doc from labels.models import Category, Span, TextLabel -from projects.models import DOCUMENT_CLASSIFICATION, SEQ2SEQ, SEQUENCE_LABELING +from projects.models import ProjectType from projects.tests.utils import prepare_project data_dir = pathlib.Path(__file__).parent / "data" @@ -19,7 +19,7 @@ class TestTemplateList(CRUDMixin): def setUp(self): - self.project = prepare_project(task=DOCUMENT_CLASSIFICATION) + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION) self.url = reverse(viewname="auto_labeling_templates", args=[self.project.item.id]) def test_allow_admin_to_fetch_template_list(self): @@ -47,7 +47,7 @@ def test_return_only_default_template_with_wrong_task_name(self): class TestConfigParameter(CRUDMixin): def setUp(self): - self.project = prepare_project(task=DOCUMENT_CLASSIFICATION) + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION) self.data = { "model_name": "GCP Entity Analysis", "model_attrs": {"key": "hoge", "type": "PLAIN_TEXT", "language": "en"}, @@ -78,7 +78,7 @@ def test_called_with_image(self, mock): class TestTemplateMapping(CRUDMixin): def setUp(self): - self.project = prepare_project(task=DOCUMENT_CLASSIFICATION) + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION) self.data = { "response": { "Sentiment": "NEUTRAL", @@ -106,7 +106,7 @@ def test_json_decode_error(self): class TestLabelMapping(CRUDMixin): def setUp(self): - self.project = prepare_project(task=DOCUMENT_CLASSIFICATION) + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION) self.data = { "response": [{"label": "NEGATIVE"}], "label_mapping": {"NEGATIVE": "Negative"}, @@ -122,7 +122,7 @@ def test_label_mapping(self): class TestConfigCreation(CRUDMixin): def setUp(self): - self.project = prepare_project(task=DOCUMENT_CLASSIFICATION) + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION) self.data = { "model_name": "Amazon Comprehend Sentiment Analysis", "model_attrs": { @@ -149,7 +149,7 @@ def test_list_config(self): class TestAutomatedLabeling(CRUDMixin): def setUp(self): - self.project = prepare_project(task=DOCUMENT_CLASSIFICATION, single_class_classification=False) + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION, single_class_classification=False) self.example = make_doc(self.project.item) self.category_pos = mommy.make("CategoryType", project=self.project.item, text="POS") self.category_neg = mommy.make("CategoryType", project=self.project.item, text="NEG") @@ -164,6 +164,12 @@ def test_category_labeling(self, mock): self.assertEqual(Category.objects.count(), 1) self.assertEqual(Category.objects.first().label, self.category_pos) + @patch("auto_labeling.views.execute_pipeline", return_value=Categories([{"label": "NEUTRAL"}])) + def test_nonexistent_category(self, mock): + mommy.make("AutoLabelingConfig", task_type="Category", project=self.project.item) + self.assert_create(self.project.admin, status.HTTP_201_CREATED) + self.assertEqual(Category.objects.count(), 0) + @patch( "auto_labeling.views.execute_pipeline", side_effect=[Categories([{"label": "POS"}]), Categories([{"label": "NEG"}])], @@ -209,7 +215,7 @@ def test_cannot_use_other_project_config(self, mock): class TestAutomatedSpanLabeling(CRUDMixin): def setUp(self): - self.project = prepare_project(task=SEQUENCE_LABELING) + self.project = prepare_project(task=ProjectType.SEQUENCE_LABELING) self.example = make_doc(self.project.item) self.loc = mommy.make("SpanType", project=self.project.item, text="LOC") self.url = reverse(viewname="auto_labeling", args=[self.project.item.id]) @@ -231,7 +237,7 @@ def test_cannot_label_overlapping_span(self, mock): class TestAutomatedTextLabeling(CRUDMixin): def setUp(self): - self.project = prepare_project(task=SEQ2SEQ) + self.project = prepare_project(task=ProjectType.SEQ2SEQ) self.example = make_doc(self.project.item) self.url = reverse(viewname="auto_labeling", args=[self.project.item.id]) self.url += f"?example={self.example.id}" diff --git a/backend/auto_labeling/views.py b/backend/auto_labeling/views.py index aa092611b5..43dfad9276 100644 --- a/backend/auto_labeling/views.py +++ b/backend/auto_labeling/views.py @@ -17,6 +17,7 @@ from .exceptions import ( AWSTokenError, + ResponseJSONDecodeError, SampleDataException, TemplateMappingError, URLConnectionError, @@ -94,6 +95,8 @@ def send_request(self, model, example): raise URLConnectionError except botocore.exceptions.ClientError: raise AWSTokenError() + except json.decoder.JSONDecodeError: + raise ResponseJSONDecodeError() except Exception as e: raise e diff --git a/backend/cli.py b/backend/cli.py index cdbfc7c67a..1864902e13 100644 --- a/backend/cli.py +++ b/backend/cli.py @@ -56,7 +56,7 @@ def load(self): "workers": args.workers, "chdir": base, "capture_output": True, - "loglevel": "debug", + "loglevel": "info", } StandaloneApplication(options).run() @@ -110,6 +110,18 @@ def command_run_task_queue(args): app.worker_main(argv=argv) +def command_run_flower(args): + print("Starting flower.") + argv = [ + "--app=config", + "--workdir={}".format(base), + "flower", + ] + if args.basic_auth: + argv.append("--basic_auth={}".format(args.basic_auth)) + app.worker_main(argv=argv) + + def command_help(args): print(parser.parse_args([args.command, "--help"])) @@ -146,6 +158,11 @@ def main(): parser_queue.add_argument("--env_file", type=str, help="read in a file of environment variables") parser_queue.set_defaults(handler=command_run_task_queue) + parser_flower = subparsers.add_parser("flower", help="see `flower -h`") + parser_flower.add_argument("--env_file", type=str, help="read in a file of environment variables") + parser_flower.add_argument("--basic_auth", type=str, help="username and password for basic authentication") + parser_flower.set_defaults(handler=command_run_flower) + # Create a parser for help. parser_help = subparsers.add_parser("help", help="see `help -h`") parser_help.add_argument("command", help="command name which help is shown") @@ -153,7 +170,7 @@ def main(): # Dispatch handler. args = parser.parse_args() - if hasattr(args, "env_file"): + if hasattr(args, "env_file") and args.env_file and Path(args.env_file).is_file(): env.read_env(args.env_file, recurse=False, override=True) if hasattr(args, "handler"): django.setup() diff --git a/backend/config/settings/aws.py b/backend/config/settings/aws.py index e9279e4e6a..988d238d54 100644 --- a/backend/config/settings/aws.py +++ b/backend/config/settings/aws.py @@ -8,6 +8,7 @@ AWS_SECRET_ACCESS_KEY = env("AWS_SECRET_ACCESS_KEY") AWS_S3_REGION_NAME = env("REGION_NAME", "us-west-1") AWS_STORAGE_BUCKET_NAME = env("BUCKET_NAME", "doccano") +AWS_S3_ENDPOINT_URL = env("AWS_S3_ENDPOINT_URL", None) AWS_DEFAULT_ACL = "private" AWS_BUCKET_ACL = "private" AWS_AUTO_CREATE_BUCKET = True diff --git a/backend/config/settings/base.py b/backend/config/settings/base.py index 863292ac4f..3048c5528a 100644 --- a/backend/config/settings/base.py +++ b/backend/config/settings/base.py @@ -10,6 +10,7 @@ Any setting that is configured via an environment variable may also be set in a `.env` file in the project base directory. """ + from os import path import dj_database_url @@ -56,7 +57,13 @@ "polymorphic", "corsheaders", "drf_yasg", + "allauth", + "allauth.account", + "allauth.socialaccount", + "allauth.socialaccount.providers.okta", "dj_rest_auth", + "dj_rest_auth.registration", + "django.contrib.sites", "django_celery_results", "django_drf_filepond", "health_check", @@ -226,8 +233,9 @@ ALLOWED_HOSTS = ["*"] if DEBUG: - CORS_ORIGIN_WHITELIST = ("http://127.0.0.1:3000", "http://0.0.0.0:3000", "http://localhost:3000") - CSRF_TRUSTED_ORIGINS = CORS_ORIGIN_WHITELIST + CORS_ORIGIN_ALLOW_ALL = True + CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:3000", "http://0.0.0.0:3000", "http://localhost:3000"] + CSRF_TRUSTED_ORIGINS += env.list("CSRF_TRUSTED_ORIGINS", []) # Batch size for importing data IMPORT_BATCH_SIZE = env.int("IMPORT_BATCH_SIZE", 1000) @@ -275,3 +283,13 @@ CELERY_RESULT_SERIALIZER = "json" DEFAULT_AUTO_FIELD = "django.db.models.AutoField" + +SOCIALACCOUNT_PROVIDERS = { + "okta": { + "OKTA_BASE_URL": env("OAUTH_OKTA_OAUTH2_API_URL", ""), + "OAUTH_PKCE_ENABLED": True, + "APP": {"client_id": env("OAUTH_OKTA_OAUTH2_KEY", ""), "secret": env("OAUTH_OKTA_OAUTH2_SECRET", "")}, + } +} + +SITE_ID = 1 diff --git a/backend/config/settings/development.py b/backend/config/settings/development.py index 64b9ace5e8..297c5ea2e6 100644 --- a/backend/config/settings/development.py +++ b/backend/config/settings/development.py @@ -1,8 +1,6 @@ from .base import * # noqa: F403 MIDDLEWARE.append("api.middleware.RangesMiddleware") # noqa: F405 -CORS_ORIGIN_WHITELIST = ("http://127.0.0.1:3000", "http://0.0.0.0:3000", "http://localhost:3000") -CSRF_TRUSTED_ORIGINS = CORS_ORIGIN_WHITELIST # LOGGING = { # 'version': 1, # 'handlers': { diff --git a/backend/config/settings/gcp.py b/backend/config/settings/gcp.py index 0046092131..34dc7626b5 100644 --- a/backend/config/settings/gcp.py +++ b/backend/config/settings/gcp.py @@ -8,4 +8,9 @@ DJANGO_DRF_FILEPOND_STORAGES_BACKEND = "storages.backends.gcloud.GoogleCloudStorage" GS_BUCKET_NAME = env("BUCKET_NAME", "doccano") GS_PROJECT_ID = env("GS_PROJECT_ID") -GS_CREDENTIALS = service_account.Credentials.from_service_account_file(env("GOOGLE_APPLICATION_CREDENTIALS")) + +# for more details refer to +# https://django-storages.readthedocs.io/en/latest/backends/gcloud.html#authentication-settings +_google_application_credentials = env("GOOGLE_APPLICATION_CREDENTIALS", "") +if _google_application_credentials: + GS_CREDENTIALS = service_account.Credentials.from_service_account_file(_google_application_credentials) diff --git a/backend/config/settings/production.py b/backend/config/settings/production.py index 255a475e06..84a6eefaeb 100644 --- a/backend/config/settings/production.py +++ b/backend/config/settings/production.py @@ -1,3 +1,31 @@ from .base import * # noqa: F401,F403 DEBUG = False + +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "standard": { + "format": "[%(asctime)s] [%(process)d] [%(levelname)s] [%(name)s::%(funcName)s::%(lineno)d] %(message)s", + "datefmt": "%Y-%m-%d %H:%M:%S %z", + } + }, + "handlers": { + "console": { + "level": "INFO", + "class": "logging.StreamHandler", + "formatter": "standard", + }, + }, + "root": { + "handlers": ["console"], + "level": "INFO", + }, + "loggers": { + "django": { + "handlers": ["console"], + "level": "INFO", + }, + }, +} diff --git a/backend/config/urls.py b/backend/config/urls.py index 80e10fe9a6..343b405745 100644 --- a/backend/config/urls.py +++ b/backend/config/urls.py @@ -13,8 +13,10 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ + import os import re +from pathlib import Path from django.conf import settings from django.contrib import admin @@ -36,6 +38,7 @@ urlpatterns = [] if settings.DEBUG or os.environ.get("STANDALONE", False): + static_dir = Path(__file__).resolve().parent.parent / "client" / "dist" # For showing images and audios in the case of pip and Docker. urlpatterns.append( re_path( @@ -44,10 +47,14 @@ {"document_root": settings.MEDIA_ROOT}, ) ) + # For showing favicon on the case of pip and Docker. + urlpatterns.append(path("favicon.ico", serve, {"document_root": static_dir, "path": "favicon.ico"})) urlpatterns += [ path("admin/", admin.site.urls), path("api-auth/", include("rest_framework.urls")), + path("social/", include("social.urls")), + path("v1/social/", include("social.v1_urls")), path("v1/health/", include("health_check.urls")), path("v1/", include("api.urls")), path("v1/", include("roles.urls")), diff --git a/backend/data_export/celery_tasks.py b/backend/data_export/celery_tasks.py index 2e273e7a7b..3b9cfcc772 100644 --- a/backend/data_export/celery_tasks.py +++ b/backend/data_export/celery_tasks.py @@ -8,7 +8,12 @@ from django.shortcuts import get_object_or_404 from .pipeline.dataset import Dataset -from .pipeline.factories import create_formatter, create_labels, create_writer +from .pipeline.factories import ( + create_comment, + create_formatter, + create_labels, + create_writer, +) from .pipeline.services import ExportApplicationService from data_export.models import ExportedExample from projects.models import Member, Project @@ -23,7 +28,8 @@ def create_collaborative_dataset(project: Project, dirpath: str, confirmed_only: else: examples = ExportedExample.objects.filter(project=project) labels = create_labels(project, examples) - dataset = Dataset(examples, labels, is_text_project) + comments = create_comment(examples) + dataset = Dataset(examples, labels, comments, is_text_project) service = ExportApplicationService(dataset, formatters, writer) @@ -40,7 +46,8 @@ def create_individual_dataset(project: Project, dirpath: str, confirmed_only: bo else: examples = ExportedExample.objects.filter(project=project) labels = create_labels(project, examples, member.user) - dataset = Dataset(examples, labels, is_text_project) + comments = create_comment(examples, member.user) + dataset = Dataset(examples, labels, comments, is_text_project) service = ExportApplicationService(dataset, formatters, writer) @@ -48,7 +55,7 @@ def create_individual_dataset(project: Project, dirpath: str, confirmed_only: bo service.export(filepath) -@shared_task +@shared_task(autoretry_for=(Exception,), retry_backoff=True, retry_jitter=True) def export_dataset(project_id, file_format: str, confirmed_only=False): project = get_object_or_404(Project, pk=project_id) dirpath = os.path.join(settings.MEDIA_ROOT, str(uuid.uuid4())) diff --git a/backend/data_export/migrations/0004_exportedcomment.py b/backend/data_export/migrations/0004_exportedcomment.py new file mode 100644 index 0000000000..04201d272b --- /dev/null +++ b/backend/data_export/migrations/0004_exportedcomment.py @@ -0,0 +1,24 @@ +# Generated by Django 4.0.4 on 2022-07-25 05:07 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("examples", "0006_alter_example_upload_name"), + ("data_export", "0003_exportedsegmentation"), + ] + + operations = [ + migrations.CreateModel( + name="ExportedComment", + fields=[], + options={ + "proxy": True, + "indexes": [], + "constraints": [], + }, + bases=("examples.comment",), + ), + ] diff --git a/backend/data_export/models.py b/backend/data_export/models.py index 6c38ea92d9..9aedc87808 100644 --- a/backend/data_export/models.py +++ b/backend/data_export/models.py @@ -2,7 +2,7 @@ from django.db import models -from examples.models import Example +from examples.models import Comment, Example from labels.models import BoundingBox, Category, Relation, Segmentation, Span, TextLabel from projects.models import Project @@ -81,6 +81,17 @@ class Meta: proxy = True +class ExportedComment(Comment): + def to_string(self) -> str: + return self.text + + def to_dict(self): + return {"id": self.id, "comment": self.text} + + class Meta: + proxy = True + + class ExportedBoundingBox(BoundingBox): def to_dict(self): return { diff --git a/backend/data_export/pipeline/catalog.py b/backend/data_export/pipeline/catalog.py index 7b19683689..93ffe7b0b6 100644 --- a/backend/data_export/pipeline/catalog.py +++ b/backend/data_export/pipeline/catalog.py @@ -2,17 +2,7 @@ from pathlib import Path from typing import Dict, List, Type -from projects.models import ( - BOUNDING_BOX, - DOCUMENT_CLASSIFICATION, - IMAGE_CAPTIONING, - IMAGE_CLASSIFICATION, - INTENT_DETECTION_AND_SLOT_FILLING, - SEGMENTATION, - SEQ2SEQ, - SEQUENCE_LABELING, - SPEECH2TEXT, -) +from projects.models import ProjectType EXAMPLE_DIR = Path(__file__).parent.resolve() / "examples" @@ -68,40 +58,40 @@ def load_example(file): # Text Classification TEXT_CLASSIFICATION_DIR = EXAMPLE_DIR / "text_classification" -Options.register(DOCUMENT_CLASSIFICATION, CSV, TEXT_CLASSIFICATION_DIR / "example.csv") -Options.register(DOCUMENT_CLASSIFICATION, FastText, TEXT_CLASSIFICATION_DIR / "example.txt") -Options.register(DOCUMENT_CLASSIFICATION, JSON, TEXT_CLASSIFICATION_DIR / "example.json") -Options.register(DOCUMENT_CLASSIFICATION, JSONL, TEXT_CLASSIFICATION_DIR / "example.jsonl") +Options.register(ProjectType.DOCUMENT_CLASSIFICATION, CSV, TEXT_CLASSIFICATION_DIR / "example.csv") +Options.register(ProjectType.DOCUMENT_CLASSIFICATION, FastText, TEXT_CLASSIFICATION_DIR / "example.txt") +Options.register(ProjectType.DOCUMENT_CLASSIFICATION, JSON, TEXT_CLASSIFICATION_DIR / "example.json") +Options.register(ProjectType.DOCUMENT_CLASSIFICATION, JSONL, TEXT_CLASSIFICATION_DIR / "example.jsonl") # Sequence Labeling SEQUENCE_LABELING_DIR = EXAMPLE_DIR / "sequence_labeling" RELATION_EXTRACTION_DIR = EXAMPLE_DIR / "relation_extraction" -Options.register(SEQUENCE_LABELING, JSONL, SEQUENCE_LABELING_DIR / "example.jsonl") -Options.register(SEQUENCE_LABELING, JSONL, RELATION_EXTRACTION_DIR / "example.jsonl", True) +Options.register(ProjectType.SEQUENCE_LABELING, JSONL, SEQUENCE_LABELING_DIR / "example.jsonl") +Options.register(ProjectType.SEQUENCE_LABELING, JSONL, RELATION_EXTRACTION_DIR / "example.jsonl", True) # Sequence to sequence SEQ2SEQ_DIR = EXAMPLE_DIR / "sequence_to_sequence" -Options.register(SEQ2SEQ, CSV, SEQ2SEQ_DIR / "example.csv") -Options.register(SEQ2SEQ, JSON, SEQ2SEQ_DIR / "example.json") -Options.register(SEQ2SEQ, JSONL, SEQ2SEQ_DIR / "example.jsonl") +Options.register(ProjectType.SEQ2SEQ, CSV, SEQ2SEQ_DIR / "example.csv") +Options.register(ProjectType.SEQ2SEQ, JSON, SEQ2SEQ_DIR / "example.json") +Options.register(ProjectType.SEQ2SEQ, JSONL, SEQ2SEQ_DIR / "example.jsonl") # Intent detection and slot filling INTENT_DETECTION_DIR = EXAMPLE_DIR / "intent_detection" -Options.register(INTENT_DETECTION_AND_SLOT_FILLING, JSONL, INTENT_DETECTION_DIR / "example.jsonl") +Options.register(ProjectType.INTENT_DETECTION_AND_SLOT_FILLING, JSONL, INTENT_DETECTION_DIR / "example.jsonl") # Image Classification IMAGE_CLASSIFICATION_DIR = EXAMPLE_DIR / "image_classification" -Options.register(IMAGE_CLASSIFICATION, JSONL, IMAGE_CLASSIFICATION_DIR / "example.jsonl") +Options.register(ProjectType.IMAGE_CLASSIFICATION, JSONL, IMAGE_CLASSIFICATION_DIR / "example.jsonl") BOUNDING_BOX_DIR = EXAMPLE_DIR / "bounding_box" -Options.register(BOUNDING_BOX, JSONL, BOUNDING_BOX_DIR / "example.jsonl") +Options.register(ProjectType.BOUNDING_BOX, JSONL, BOUNDING_BOX_DIR / "example.jsonl") SEGMENTATION_DIR = EXAMPLE_DIR / "segmentation" -Options.register(SEGMENTATION, JSONL, SEGMENTATION_DIR / "example.jsonl") +Options.register(ProjectType.SEGMENTATION, JSONL, SEGMENTATION_DIR / "example.jsonl") IMAGE_CAPTIONING_DIR = EXAMPLE_DIR / "image_captioning" -Options.register(IMAGE_CAPTIONING, JSONL, IMAGE_CAPTIONING_DIR / "example.jsonl") +Options.register(ProjectType.IMAGE_CAPTIONING, JSONL, IMAGE_CAPTIONING_DIR / "example.jsonl") # Speech to Text SPEECH2TEXT_DIR = EXAMPLE_DIR / "speech_to_text" -Options.register(SPEECH2TEXT, JSONL, SPEECH2TEXT_DIR / "example.jsonl") +Options.register(ProjectType.SPEECH2TEXT, JSONL, SPEECH2TEXT_DIR / "example.jsonl") diff --git a/backend/data_export/pipeline/comments.py b/backend/data_export/pipeline/comments.py new file mode 100644 index 0000000000..1e42428e31 --- /dev/null +++ b/backend/data_export/pipeline/comments.py @@ -0,0 +1,24 @@ +import abc +from collections import defaultdict +from typing import Dict, List, Tuple + +from django.db.models import QuerySet + +from data_export.models import ExportedComment, ExportedExample + + +class Comments(abc.ABC): + comment_class = ExportedComment + column = "Comments" + fields: Tuple[str, ...] = ("example", "user") # To boost performance + + def __init__(self, examples: QuerySet[ExportedExample], user=None): + self.comment_groups = defaultdict(list) + comments = self.comment_class.objects.filter(example__in=examples) + if user: + comments = comments.filter(user=user) + for comment in comments.select_related(*self.fields): + self.comment_groups[comment.example.id].append(comment) + + def find_by(self, example_id: int) -> Dict[str, List[ExportedComment]]: + return {self.column: self.comment_groups[example_id]} diff --git a/backend/data_export/pipeline/dataset.py b/backend/data_export/pipeline/dataset.py index 9d1847048a..c2c85c849e 100644 --- a/backend/data_export/pipeline/dataset.py +++ b/backend/data_export/pipeline/dataset.py @@ -3,21 +3,27 @@ import pandas as pd from django.db.models.query import QuerySet +from .comments import Comments from .labels import Labels from data_export.models import ExportedExample class Dataset: - def __init__(self, examples: QuerySet[ExportedExample], labels: List[Labels], is_text_project=True): + def __init__( + self, examples: QuerySet[ExportedExample], labels: List[Labels], comments: List[Comments], is_text_project=True + ): self.examples = examples self.labels = labels self.is_text_project = is_text_project + self.comments = comments def __iter__(self) -> Iterator[Dict[str, Any]]: for example in self.examples: data = example.to_dict(self.is_text_project) for labels in self.labels: data.update(**labels.find_by(example.id)) + for comment in self.comments: + data.update(**comment.find_by(example.id)) yield data def to_dataframe(self) -> pd.DataFrame: diff --git a/backend/data_export/pipeline/factories.py b/backend/data_export/pipeline/factories.py index 1dcf6fb9a0..c4dc7bb9ac 100644 --- a/backend/data_export/pipeline/factories.py +++ b/backend/data_export/pipeline/factories.py @@ -4,6 +4,7 @@ from . import writers from .catalog import CSV, JSON, JSONL, FastText +from .comments import Comments from .formatters import ( DictFormatter, FastTextCategoryFormatter, @@ -15,18 +16,7 @@ ) from .labels import BoundingBoxes, Categories, Labels, Relations, Segments, Spans, Texts from data_export.models import DATA, ExportedExample -from projects.models import ( - BOUNDING_BOX, - DOCUMENT_CLASSIFICATION, - IMAGE_CAPTIONING, - IMAGE_CLASSIFICATION, - INTENT_DETECTION_AND_SLOT_FILLING, - SEGMENTATION, - SEQ2SEQ, - SEQUENCE_LABELING, - SPEECH2TEXT, - Project, -) +from projects.models import Project, ProjectType def create_writer(file_format: str) -> writers.Writer: @@ -60,55 +50,99 @@ def create_formatter(project: Project, file_format: str) -> List[Formatter]: mapper_speech2text = {DATA: "filename", Texts.column: "label"} mapping: Dict[str, Dict[str, List[Formatter]]] = { - DOCUMENT_CLASSIFICATION: { + ProjectType.DOCUMENT_CLASSIFICATION: { CSV.name: [ JoinedCategoryFormatter(Categories.column), + JoinedCategoryFormatter(Comments.column), RenameFormatter(**mapper_text_classification), ], JSON.name: [ ListedCategoryFormatter(Categories.column), + ListedCategoryFormatter(Comments.column), RenameFormatter(**mapper_text_classification), ], JSONL.name: [ ListedCategoryFormatter(Categories.column), + ListedCategoryFormatter(Comments.column), RenameFormatter(**mapper_text_classification), ], FastText.name: [FastTextCategoryFormatter(Categories.column)], }, - SEQUENCE_LABELING: { - JSONL.name: [ - DictFormatter(Spans.column), - DictFormatter(Relations.column), - RenameFormatter(**mapper_relation_extraction), - ] - if use_relation - else [TupledSpanFormatter(Spans.column), RenameFormatter(**mapper_sequence_labeling)] + ProjectType.SEQUENCE_LABELING: { + JSONL.name: ( + [ + DictFormatter(Spans.column), + DictFormatter(Relations.column), + DictFormatter(Comments.column), + RenameFormatter(**mapper_relation_extraction), + ] + if use_relation + else [ + TupledSpanFormatter(Spans.column), + ListedCategoryFormatter(Comments.column), + RenameFormatter(**mapper_sequence_labeling), + ] + ) }, - SEQ2SEQ: { - CSV.name: [JoinedCategoryFormatter(Texts.column), RenameFormatter(**mapper_seq2seq)], - JSON.name: [ListedCategoryFormatter(Texts.column), RenameFormatter(**mapper_seq2seq)], - JSONL.name: [ListedCategoryFormatter(Texts.column), RenameFormatter(**mapper_seq2seq)], + ProjectType.SEQ2SEQ: { + CSV.name: [ + JoinedCategoryFormatter(Texts.column), + JoinedCategoryFormatter(Comments.column), + RenameFormatter(**mapper_seq2seq), + ], + JSON.name: [ + ListedCategoryFormatter(Texts.column), + ListedCategoryFormatter(Comments.column), + RenameFormatter(**mapper_seq2seq), + ], + JSONL.name: [ + ListedCategoryFormatter(Texts.column), + ListedCategoryFormatter(Comments.column), + RenameFormatter(**mapper_seq2seq), + ], }, - IMAGE_CLASSIFICATION: { + ProjectType.IMAGE_CLASSIFICATION: { JSONL.name: [ ListedCategoryFormatter(Categories.column), + ListedCategoryFormatter(Comments.column), RenameFormatter(**mapper_image_classification), ], }, - SPEECH2TEXT: { - JSONL.name: [ListedCategoryFormatter(Texts.column), RenameFormatter(**mapper_speech2text)], + ProjectType.SPEECH2TEXT: { + JSONL.name: [ + ListedCategoryFormatter(Texts.column), + ListedCategoryFormatter(Comments.column), + RenameFormatter(**mapper_speech2text), + ], }, - INTENT_DETECTION_AND_SLOT_FILLING: { + ProjectType.INTENT_DETECTION_AND_SLOT_FILLING: { JSONL.name: [ ListedCategoryFormatter(Categories.column), TupledSpanFormatter(Spans.column), + ListedCategoryFormatter(Comments.column), RenameFormatter(**mapper_intent_detection), ] }, - BOUNDING_BOX: {JSONL.name: [DictFormatter(BoundingBoxes.column), RenameFormatter(**mapper_bounding_box)]}, - SEGMENTATION: {JSONL.name: [DictFormatter(Segments.column), RenameFormatter(**mapper_segmentation)]}, - IMAGE_CAPTIONING: { - JSONL.name: [ListedCategoryFormatter(Texts.column), RenameFormatter(**mapper_image_captioning)] + ProjectType.BOUNDING_BOX: { + JSONL.name: [ + DictFormatter(BoundingBoxes.column), + DictFormatter(Comments.column), + RenameFormatter(**mapper_bounding_box), + ] + }, + ProjectType.SEGMENTATION: { + JSONL.name: [ + DictFormatter(Segments.column), + DictFormatter(Comments.column), + RenameFormatter(**mapper_segmentation), + ] + }, + ProjectType.IMAGE_CAPTIONING: { + JSONL.name: [ + ListedCategoryFormatter(Texts.column), + ListedCategoryFormatter(Comments.column), + RenameFormatter(**mapper_image_captioning), + ] }, } return mapping[project.project_type][file_format] @@ -117,15 +151,15 @@ def create_formatter(project: Project, file_format: str) -> List[Formatter]: def select_label_collection(project: Project) -> List[Type[Labels]]: use_relation = getattr(project, "use_relation", False) mapping: Dict[str, List[Type[Labels]]] = { - DOCUMENT_CLASSIFICATION: [Categories], - SEQUENCE_LABELING: [Spans, Relations] if use_relation else [Spans], - SEQ2SEQ: [Texts], - IMAGE_CLASSIFICATION: [Categories], - SPEECH2TEXT: [Texts], - INTENT_DETECTION_AND_SLOT_FILLING: [Categories, Spans], - BOUNDING_BOX: [BoundingBoxes], - SEGMENTATION: [Segments], - IMAGE_CAPTIONING: [Texts], + ProjectType.DOCUMENT_CLASSIFICATION: [Categories], + ProjectType.SEQUENCE_LABELING: [Spans, Relations] if use_relation else [Spans], + ProjectType.SEQ2SEQ: [Texts], + ProjectType.IMAGE_CLASSIFICATION: [Categories], + ProjectType.SPEECH2TEXT: [Texts], + ProjectType.INTENT_DETECTION_AND_SLOT_FILLING: [Categories, Spans], + ProjectType.BOUNDING_BOX: [BoundingBoxes], + ProjectType.SEGMENTATION: [Segments], + ProjectType.IMAGE_CAPTIONING: [Texts], } return mapping[project.project_type] @@ -134,3 +168,7 @@ def create_labels(project: Project, examples: QuerySet[ExportedExample], user=No label_collections = select_label_collection(project) labels = [label_collection(examples=examples, user=user) for label_collection in label_collections] return labels + + +def create_comment(examples: QuerySet[ExportedExample], user=None) -> List[Comments]: + return [Comments(examples=examples, user=user)] diff --git a/backend/data_export/pipeline/formatters.py b/backend/data_export/pipeline/formatters.py index 56b9144e73..2051b3d66f 100644 --- a/backend/data_export/pipeline/formatters.py +++ b/backend/data_export/pipeline/formatters.py @@ -1,6 +1,7 @@ """ Convert a dataset to the specified format. """ + import abc import pandas as pd @@ -46,12 +47,15 @@ def apply(self, dataset: pd.DataFrame) -> pd.DataFrame: """Format the label column to `__label__LabelA __label__LabelB` format. Also, drop the columns except for `data` and `self.target_column`. """ - dataset = dataset[[DATA, self.target_column]] + dataset = dataset[[DATA, self.target_column, "Comments"]] dataset[self.target_column] = dataset[self.target_column].apply( lambda labels: " ".join(sorted(f"__label__{label.to_string()}" for label in labels)) ) dataset[self.target_column] = dataset[self.target_column].fillna("") - dataset = dataset[self.target_column] + " " + dataset[DATA] + dataset["Comments"] = dataset["Comments"].apply( + lambda comments: " ".join(f"__comment__{comment.to_string()}" for comment in comments) + ) + dataset = dataset[self.target_column] + " " + dataset[DATA] + " " + dataset["Comments"] return dataset diff --git a/backend/data_export/pipeline/labels.py b/backend/data_export/pipeline/labels.py index af35ea135f..a6a442cf6b 100644 --- a/backend/data_export/pipeline/labels.py +++ b/backend/data_export/pipeline/labels.py @@ -1,6 +1,7 @@ """ Represents label collection. """ + import abc from collections import defaultdict from typing import Dict, List, Tuple diff --git a/backend/data_export/tests/test_catalog.py b/backend/data_export/tests/test_catalog.py index f2c4c2888b..b0dcd7242a 100644 --- a/backend/data_export/tests/test_catalog.py +++ b/backend/data_export/tests/test_catalog.py @@ -1,33 +1,12 @@ import unittest from ..pipeline.catalog import Options -from projects.models import ( - BOUNDING_BOX, - DOCUMENT_CLASSIFICATION, - IMAGE_CAPTIONING, - IMAGE_CLASSIFICATION, - INTENT_DETECTION_AND_SLOT_FILLING, - SEGMENTATION, - SEQ2SEQ, - SEQUENCE_LABELING, - SPEECH2TEXT, -) +from projects.models import ProjectType class TestOptions(unittest.TestCase): def test_return_at_least_one_option(self): - tasks = [ - BOUNDING_BOX, - DOCUMENT_CLASSIFICATION, - IMAGE_CAPTIONING, - IMAGE_CLASSIFICATION, - INTENT_DETECTION_AND_SLOT_FILLING, - SEGMENTATION, - SEQ2SEQ, - SEQUENCE_LABELING, - SPEECH2TEXT, - ] - for task in tasks: + for task in ProjectType: with self.subTest(task=task): options = Options.filter_by_task(task) self.assertGreaterEqual(len(options), 1) diff --git a/backend/data_export/tests/test_dataset.py b/backend/data_export/tests/test_dataset.py index f7029ebf8b..9ec57a376c 100644 --- a/backend/data_export/tests/test_dataset.py +++ b/backend/data_export/tests/test_dataset.py @@ -17,9 +17,13 @@ def setUp(self): label.find_by.return_value = {"labels": ["label"]} self.labels = MagicMock() self.labels.__iter__.return_value = [label] + comment = MagicMock() + comment.find_by.return_value = {"comments": ["comment"]} + self.comments = MagicMock() + self.comments.__iter__.return_value = [comment] def test_to_dataframe(self): - dataset = Dataset(self.examples, self.labels) + dataset = Dataset(self.examples, self.labels, self.comments) df = dataset.to_dataframe() - expected = pd.DataFrame([{"data": "example", "labels": ["label"]}]) + expected = pd.DataFrame([{"data": "example", "labels": ["label"], "comments": ["comment"]}]) assert_frame_equal(df, expected) diff --git a/backend/data_export/tests/test_formatters.py b/backend/data_export/tests/test_formatters.py index cb371b3a8e..c1c316611f 100644 --- a/backend/data_export/tests/test_formatters.py +++ b/backend/data_export/tests/test_formatters.py @@ -75,15 +75,20 @@ def test_format(self): class TestFastTextFormatter(unittest.TestCase): def setUp(self): - self.return_value = "Label" + self.return_value_label = "Label" + self.return_value_comment = "Comment" label = MagicMock() - label.to_string.return_value = self.return_value - self.dataset = pd.DataFrame([{TARGET_COLUMN: [label], DATA: "example"}]) + comment = MagicMock() + label.to_string.return_value = self.return_value_label + comment.to_string.return_value = self.return_value_comment + self.dataset = pd.DataFrame([{TARGET_COLUMN: [label], DATA: "example", "Comments": [comment]}]) def test_format(self): formatter = FastTextCategoryFormatter(TARGET_COLUMN) dataset = formatter.format(self.dataset) - expected_dataset = pd.DataFrame([f"__label__{self.return_value} example"]) + expected_dataset = pd.DataFrame( + [f"__label__{self.return_value_label} example __comment__{self.return_value_comment}"] + ) self.assertEqual(dataset.to_csv(index=False, header=None), expected_dataset.to_csv(index=False, header=None)) diff --git a/backend/data_export/tests/test_labels.py b/backend/data_export/tests/test_labels.py index 5bbc6c44f2..6511dae205 100644 --- a/backend/data_export/tests/test_labels.py +++ b/backend/data_export/tests/test_labels.py @@ -3,13 +3,13 @@ from ..pipeline.labels import Categories from data_export.models import ExportedExample -from projects.models import DOCUMENT_CLASSIFICATION +from projects.models import ProjectType from projects.tests.utils import prepare_project class TestLabels(TestCase): def setUp(self): - self.project = prepare_project(task=DOCUMENT_CLASSIFICATION) + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION) self.example1 = mommy.make("ExportedExample", project=self.project.item) self.example2 = mommy.make("ExportedExample", project=self.project.item) self.category1 = mommy.make("ExportedCategory", example=self.example1, user=self.project.admin) diff --git a/backend/data_export/tests/test_task.py b/backend/data_export/tests/test_task.py index 63289217ba..97f9a1fdf2 100644 --- a/backend/data_export/tests/test_task.py +++ b/backend/data_export/tests/test_task.py @@ -7,17 +7,7 @@ from ..celery_tasks import export_dataset from data_export.models import DATA -from projects.models import ( - BOUNDING_BOX, - DOCUMENT_CLASSIFICATION, - IMAGE_CAPTIONING, - IMAGE_CLASSIFICATION, - INTENT_DETECTION_AND_SLOT_FILLING, - SEGMENTATION, - SEQ2SEQ, - SEQUENCE_LABELING, - SPEECH2TEXT, -) +from projects.models import ProjectType from projects.tests.utils import prepare_project @@ -59,11 +49,13 @@ def data_to_filename(self, example): class TestExportCategory(TestExport): def prepare_data(self, collaborative=False): - self.project = prepare_project(DOCUMENT_CLASSIFICATION, collaborative_annotation=collaborative) + self.project = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION, collaborative_annotation=collaborative) self.example1 = mommy.make("ExportedExample", project=self.project.item, text="example1") self.example2 = mommy.make("ExportedExample", project=self.project.item, text="example2") self.category1 = mommy.make("ExportedCategory", example=self.example1, user=self.project.admin) self.category2 = mommy.make("ExportedCategory", example=self.example1, user=self.project.annotator) + self.comment1 = mommy.make("ExportedComment", example=self.example1, user=self.project.admin) + self.comment2 = mommy.make("ExportedComment", example=self.example1, user=self.project.annotator) mommy.make("ExampleState", example=self.example1, confirmed_by=self.project.admin) self.data1 = self.data_to_text(self.example1) self.data2 = self.data_to_text(self.example2) @@ -73,16 +65,16 @@ def test_unconfirmed_and_non_collaborative(self): datasets = self.export_dataset() expected_datasets = { self.project.admin.username: [ - {**self.data1, "label": [self.category1.to_string()]}, - {**self.data2, "label": []}, + {**self.data1, "label": [self.category1.to_string()], "Comments": [self.comment1.to_string()]}, + {**self.data2, "label": [], "Comments": []}, ], self.project.approver.username: [ - {**self.data1, "label": []}, - {**self.data2, "label": []}, + {**self.data1, "label": [], "Comments": []}, + {**self.data2, "label": [], "Comments": []}, ], self.project.annotator.username: [ - {**self.data1, "label": [self.category2.to_string()]}, - {**self.data2, "label": []}, + {**self.data1, "label": [self.category2.to_string()], "Comments": [self.comment2.to_string()]}, + {**self.data2, "label": [], "Comments": []}, ], } for username, dataset in expected_datasets.items(): @@ -95,15 +87,20 @@ def test_unconfirmed_and_collaborative(self): { **self.data1, "label": sorted([self.category1.to_string(), self.category2.to_string()]), + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), }, - {**self.data2, "label": []}, + {**self.data2, "label": [], "Comments": []}, ] self.assertEqual(dataset, expected_dataset) def test_confirmed_and_non_collaborative(self): self.prepare_data() datasets = self.export_dataset(confirmed_only=True) - expected_datasets = {self.project.admin.username: [{**self.data1, "label": [self.category1.to_string()]}]} + expected_datasets = { + self.project.admin.username: [ + {**self.data1, "label": [self.category1.to_string()], "Comments": [self.comment1.to_string()]} + ] + } for username, dataset in expected_datasets.items(): self.assertEqual(datasets[username], dataset) @@ -114,6 +111,7 @@ def test_confirmed_and_collaborative(self): { **self.data1, "label": sorted([self.category1.to_string(), self.category2.to_string()]), + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), } ] self.assertEqual(dataset, expected_dataset) @@ -121,11 +119,13 @@ def test_confirmed_and_collaborative(self): class TestExportSeq2seq(TestExport): def prepare_data(self, collaborative=False): - self.project = prepare_project(SEQ2SEQ, collaborative_annotation=collaborative) + self.project = prepare_project(ProjectType.SEQ2SEQ, collaborative_annotation=collaborative) self.example1 = mommy.make("ExportedExample", project=self.project.item, text="confirmed") self.example2 = mommy.make("ExportedExample", project=self.project.item, text="unconfirmed") self.text1 = mommy.make("TextLabel", example=self.example1, user=self.project.admin) self.text2 = mommy.make("TextLabel", example=self.example1, user=self.project.annotator) + self.comment1 = mommy.make("ExportedComment", example=self.example1, user=self.project.admin) + self.comment2 = mommy.make("ExportedComment", example=self.example1, user=self.project.annotator) mommy.make("ExampleState", example=self.example1, confirmed_by=self.project.admin) self.data1 = self.data_to_text(self.example1) self.data2 = self.data_to_text(self.example2) @@ -135,16 +135,16 @@ def test_unconfirmed_and_non_collaborative(self): datasets = self.export_dataset() expected_datasets = { self.project.admin.username: [ - {**self.data1, "label": [self.text1.text]}, - {**self.data2, "label": []}, + {**self.data1, "label": [self.text1.text], "Comments": [self.comment1.to_string()]}, + {**self.data2, "label": [], "Comments": []}, ], self.project.approver.username: [ - {**self.data1, "label": []}, - {**self.data2, "label": []}, + {**self.data1, "label": [], "Comments": []}, + {**self.data2, "label": [], "Comments": []}, ], self.project.annotator.username: [ - {**self.data1, "label": [self.text2.text]}, - {**self.data2, "label": []}, + {**self.data1, "label": [self.text2.text], "Comments": [self.comment2.to_string()]}, + {**self.data2, "label": [], "Comments": []}, ], } for username, dataset in expected_datasets.items(): @@ -157,8 +157,9 @@ def test_unconfirmed_and_collaborative(self): { **self.data1, "label": sorted([self.text1.text, self.text2.text]), + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), }, - {**self.data2, "label": []}, + {**self.data2, "label": [], "Comments": []}, ] self.assertEqual(dataset, expected_dataset) @@ -167,7 +168,7 @@ def test_confirmed_and_non_collaborative(self): datasets = self.export_dataset(confirmed_only=True) expected_datasets = { self.project.admin.username: [ - {**self.data1, "label": [self.text1.text]}, + {**self.data1, "label": [self.text1.text], "Comments": [self.comment1.to_string()]}, ], self.project.approver.username: [], self.project.annotator.username: [], @@ -182,6 +183,7 @@ def test_confirmed_and_collaborative(self): { **self.data1, "label": sorted([self.text1.text, self.text2.text]), + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), } ] self.assertEqual(dataset, expected_dataset) @@ -189,11 +191,15 @@ def test_confirmed_and_collaborative(self): class TestExportIntentDetectionAndSlotFilling(TestExport): def prepare_data(self, collaborative=False): - self.project = prepare_project(INTENT_DETECTION_AND_SLOT_FILLING, collaborative_annotation=collaborative) + self.project = prepare_project( + ProjectType.INTENT_DETECTION_AND_SLOT_FILLING, collaborative_annotation=collaborative + ) self.example1 = mommy.make("ExportedExample", project=self.project.item, text="confirmed") self.example2 = mommy.make("ExportedExample", project=self.project.item, text="unconfirmed") self.category1 = mommy.make("ExportedCategory", example=self.example1, user=self.project.admin) self.category2 = mommy.make("ExportedCategory", example=self.example1, user=self.project.annotator) + self.comment1 = mommy.make("ExportedComment", example=self.example1, user=self.project.admin) + self.comment2 = mommy.make("ExportedComment", example=self.example1, user=self.project.annotator) self.span = mommy.make( "ExportedSpan", example=self.example1, user=self.project.admin, start_offset=0, end_offset=1 ) @@ -210,20 +216,22 @@ def test_unconfirmed_and_non_collaborative(self): **self.data1, "entities": [list(self.span.to_tuple())], "cats": [self.category1.to_string()], + "Comments": [self.comment1.to_string()], }, - {**self.data2, "entities": [], "cats": []}, + {**self.data2, "entities": [], "cats": [], "Comments": []}, ], self.project.annotator.username: [ { **self.data1, "entities": [], "cats": [self.category2.to_string()], + "Comments": [self.comment2.to_string()], }, - {**self.data2, "entities": [], "cats": []}, + {**self.data2, "entities": [], "cats": [], "Comments": []}, ], self.project.approver.username: [ - {**self.data1, "entities": [], "cats": []}, - {**self.data2, "entities": [], "cats": []}, + {**self.data1, "entities": [], "cats": [], "Comments": []}, + {**self.data2, "entities": [], "cats": [], "Comments": []}, ], } for username, dataset in expected_datasets.items(): @@ -237,8 +245,9 @@ def test_unconfirmed_and_collaborative(self): **self.data1, "entities": [list(self.span.to_tuple())], "cats": sorted([self.category1.to_string(), self.category2.to_string()]), + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), }, - {**self.data2, "entities": [], "cats": []}, + {**self.data2, "entities": [], "cats": [], "Comments": []}, ] self.assertEqual(dataset, expected_dataset) @@ -251,6 +260,7 @@ def test_confirmed_and_non_collaborative(self): **self.data1, "entities": [list(self.span.to_tuple())], "cats": [self.category1.to_string()], + "Comments": [self.comment1.to_string()], }, ], self.project.annotator.username: [], @@ -267,6 +277,7 @@ def test_confirmed_and_collaborative(self): **self.data1, "entities": [list(self.span.to_tuple())], "cats": sorted([self.category1.to_string(), self.category2.to_string()]), + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), }, ] self.assertEqual(dataset, expected_dataset) @@ -274,7 +285,7 @@ def test_confirmed_and_collaborative(self): class TestExportSequenceLabeling(TestExport): def prepare_data(self, collaborative=False): - self.project = prepare_project(SEQUENCE_LABELING, collaborative_annotation=collaborative) + self.project = prepare_project(ProjectType.SEQUENCE_LABELING, collaborative_annotation=collaborative) self.example1 = mommy.make("ExportedExample", project=self.project.item, text="confirmed") self.span1 = mommy.make( "ExportedSpan", example=self.example1, user=self.project.admin, start_offset=0, end_offset=1 @@ -284,6 +295,8 @@ def prepare_data(self, collaborative=False): ) mommy.make("ExampleState", example=self.example1, confirmed_by=self.project.admin) self.example2 = mommy.make("ExportedExample", project=self.project.item, text="unconfirmed") + self.comment1 = mommy.make("ExportedComment", example=self.example1, user=self.project.admin) + self.comment2 = mommy.make("ExportedComment", example=self.example1, user=self.project.annotator) self.data1 = self.data_to_text(self.example1) self.data2 = self.data_to_text(self.example2) @@ -292,16 +305,16 @@ def test_unconfirmed_and_non_collaborative(self): datasets = self.export_dataset() expected_datasets = { self.project.admin.username: [ - {**self.data1, "label": [list(self.span1.to_tuple())]}, - {**self.data2, "label": []}, + {**self.data1, "label": [list(self.span1.to_tuple())], "Comments": [self.comment1.to_string()]}, + {**self.data2, "label": [], "Comments": []}, ], self.project.annotator.username: [ - {**self.data1, "label": [list(self.span2.to_tuple())]}, - {**self.data2, "label": []}, + {**self.data1, "label": [list(self.span2.to_tuple())], "Comments": [self.comment2.to_string()]}, + {**self.data2, "label": [], "Comments": []}, ], self.project.approver.username: [ - {**self.data1, "label": []}, - {**self.data2, "label": []}, + {**self.data1, "label": [], "Comments": []}, + {**self.data2, "label": [], "Comments": []}, ], } for username, dataset in expected_datasets.items(): @@ -314,8 +327,9 @@ def test_unconfirmed_and_collaborative(self): { **self.data1, "label": [list(self.span1.to_tuple()), list(self.span2.to_tuple())], + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), }, - {**self.data2, "label": []}, + {**self.data2, "label": [], "Comments": []}, ] self.assertEqual(dataset, expected_dataset) @@ -324,7 +338,7 @@ def test_confirmed_and_non_collaborative(self): datasets = self.export_dataset(confirmed_only=True) expected_datasets = { self.project.admin.username: [ - {**self.data1, "label": [list(self.span1.to_tuple())]}, + {**self.data1, "label": [list(self.span1.to_tuple())], "Comments": [self.comment1.to_string()]}, ], self.project.annotator.username: [], self.project.approver.username: [], @@ -339,6 +353,7 @@ def test_confirmed_and_collaborative(self): { **self.data1, "label": [list(self.span1.to_tuple()), list(self.span2.to_tuple())], + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), }, ] self.assertEqual(dataset, expected_dataset) @@ -346,11 +361,13 @@ def test_confirmed_and_collaborative(self): class TestExportSpeechToText(TestExport): def prepare_data(self, collaborative=False): - self.project = prepare_project(SPEECH2TEXT, collaborative_annotation=collaborative) + self.project = prepare_project(ProjectType.SPEECH2TEXT, collaborative_annotation=collaborative) self.example1 = mommy.make("ExportedExample", project=self.project.item, text="confirmed") self.example2 = mommy.make("ExportedExample", project=self.project.item, text="unconfirmed") self.text1 = mommy.make("TextLabel", example=self.example1, user=self.project.admin) self.text2 = mommy.make("TextLabel", example=self.example1, user=self.project.annotator) + self.comment1 = mommy.make("ExportedComment", example=self.example1, user=self.project.admin) + self.comment2 = mommy.make("ExportedComment", example=self.example1, user=self.project.annotator) mommy.make("ExampleState", example=self.example1, confirmed_by=self.project.admin) self.data1 = self.data_to_filename(self.example1) self.data2 = self.data_to_filename(self.example2) @@ -360,16 +377,16 @@ def test_unconfirmed_and_non_collaborative(self): datasets = self.export_dataset() expected_datasets = { self.project.admin.username: [ - {**self.data1, "label": [self.text1.text]}, - {**self.data2, "label": []}, + {**self.data1, "label": [self.text1.text], "Comments": [self.comment1.to_string()]}, + {**self.data2, "label": [], "Comments": []}, ], self.project.approver.username: [ - {**self.data1, "label": []}, - {**self.data2, "label": []}, + {**self.data1, "label": [], "Comments": []}, + {**self.data2, "label": [], "Comments": []}, ], self.project.annotator.username: [ - {**self.data1, "label": [self.text2.text]}, - {**self.data2, "label": []}, + {**self.data1, "label": [self.text2.text], "Comments": [self.comment2.to_string()]}, + {**self.data2, "label": [], "Comments": []}, ], } for username, dataset in expected_datasets.items(): @@ -382,8 +399,9 @@ def test_unconfirmed_and_collaborative(self): { **self.data1, "label": sorted([self.text1.text, self.text2.text]), + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), }, - {**self.data2, "label": []}, + {**self.data2, "label": [], "Comments": []}, ] self.assertEqual(dataset, expected_dataset) @@ -392,7 +410,7 @@ def test_confirmed_and_non_collaborative(self): datasets = self.export_dataset(confirmed_only=True) expected_datasets = { self.project.admin.username: [ - {**self.data1, "label": [self.text1.text]}, + {**self.data1, "label": [self.text1.text], "Comments": [self.comment1.to_string()]}, ], self.project.annotator.username: [], self.project.approver.username: [], @@ -407,6 +425,7 @@ def test_confirmed_and_collaborative(self): { **self.data1, "label": sorted([self.text1.text, self.text2.text]), + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), } ] self.assertEqual(dataset, expected_dataset) @@ -414,11 +433,13 @@ def test_confirmed_and_collaborative(self): class TestExportImageClassification(TestExport): def prepare_data(self, collaborative=False): - self.project = prepare_project(IMAGE_CLASSIFICATION, collaborative_annotation=collaborative) + self.project = prepare_project(ProjectType.IMAGE_CLASSIFICATION, collaborative_annotation=collaborative) self.example1 = mommy.make("ExportedExample", project=self.project.item, text="confirmed") self.example2 = mommy.make("ExportedExample", project=self.project.item, text="unconfirmed") self.category1 = mommy.make("ExportedCategory", example=self.example1, user=self.project.admin) self.category2 = mommy.make("ExportedCategory", example=self.example1, user=self.project.annotator) + self.comment1 = mommy.make("ExportedComment", example=self.example1, user=self.project.admin) + self.comment2 = mommy.make("ExportedComment", example=self.example1, user=self.project.annotator) mommy.make("ExampleState", example=self.example1, confirmed_by=self.project.admin) self.data1 = self.data_to_filename(self.example1) self.data2 = self.data_to_filename(self.example2) @@ -428,22 +449,16 @@ def test_unconfirmed_and_non_collaborative(self): datasets = self.export_dataset() expected_datasets = { self.project.admin.username: [ - { - **self.data1, - "label": [self.category1.to_string()], - }, - {**self.data2, "label": []}, + {**self.data1, "label": [self.category1.to_string()], "Comments": [self.comment1.to_string()]}, + {**self.data2, "label": [], "Comments": []}, ], self.project.approver.username: [ - {**self.data1, "label": []}, - {**self.data2, "label": []}, + {**self.data1, "label": [], "Comments": []}, + {**self.data2, "label": [], "Comments": []}, ], self.project.annotator.username: [ - { - **self.data1, - "label": [self.category2.to_string()], - }, - {**self.data2, "label": []}, + {**self.data1, "label": [self.category2.to_string()], "Comments": [self.comment2.to_string()]}, + {**self.data2, "label": [], "Comments": []}, ], } for username, dataset in expected_datasets.items(): @@ -456,15 +471,20 @@ def test_unconfirmed_and_collaborative(self): { **self.data1, "label": sorted([self.category1.to_string(), self.category2.to_string()]), + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), }, - {**self.data2, "label": []}, + {**self.data2, "label": [], "Comments": []}, ] self.assertEqual(dataset, expected_dataset) def test_confirmed_and_non_collaborative(self): self.prepare_data() datasets = self.export_dataset(confirmed_only=True) - expected_datasets = {self.project.admin.username: [{**self.data1, "label": [self.category1.to_string()]}]} + expected_datasets = { + self.project.admin.username: [ + {**self.data1, "label": [self.category1.to_string()], "Comments": [self.comment1.to_string()]} + ] + } for username, dataset in expected_datasets.items(): self.assertEqual(datasets[username], dataset) @@ -475,6 +495,7 @@ def test_confirmed_and_collaborative(self): { **self.data1, "label": sorted([self.category1.to_string(), self.category2.to_string()]), + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), } ] self.assertEqual(dataset, expected_dataset) @@ -482,9 +503,11 @@ def test_confirmed_and_collaborative(self): class TestExportBoundingBox(TestExport): def prepare_data(self, collaborative=False): - self.project = prepare_project(BOUNDING_BOX, collaborative_annotation=collaborative) + self.project = prepare_project(ProjectType.BOUNDING_BOX, collaborative_annotation=collaborative) self.example1 = mommy.make("ExportedExample", project=self.project.item, text="confirmed") self.example2 = mommy.make("ExportedExample", project=self.project.item, text="unconfirmed") + self.comment1 = mommy.make("ExportedComment", example=self.example1, user=self.project.admin) + self.comment2 = mommy.make("ExportedComment", example=self.example1, user=self.project.annotator) self.bbox1 = mommy.make( "ExportedBoundingBox", example=self.example1, user=self.project.admin, x=0, y=0, width=10, height=10 ) @@ -503,19 +526,17 @@ def test_unconfirmed_and_non_collaborative(self): { **self.data1, "bbox": [self.bbox1.to_dict()], + "Comments": [self.comment1.to_dict()], }, - {**self.data2, "bbox": []}, + {**self.data2, "bbox": [], "Comments": []}, ], self.project.approver.username: [ - {**self.data1, "bbox": []}, - {**self.data2, "bbox": []}, + {**self.data1, "bbox": [], "Comments": []}, + {**self.data2, "bbox": [], "Comments": []}, ], self.project.annotator.username: [ - { - **self.data1, - "bbox": [self.bbox2.to_dict()], - }, - {**self.data2, "bbox": []}, + {**self.data1, "bbox": [self.bbox2.to_dict()], "Comments": [self.comment2.to_dict()]}, + {**self.data2, "bbox": [], "Comments": []}, ], } for username, dataset in expected_datasets.items(): @@ -528,15 +549,20 @@ def test_unconfirmed_and_collaborative(self): { **self.data1, "bbox": [self.bbox1.to_dict(), self.bbox2.to_dict()], + "Comments": [self.comment1.to_dict(), self.comment2.to_dict()], }, - {**self.data2, "bbox": []}, + {**self.data2, "bbox": [], "Comments": []}, ] self.assertEqual(dataset, expected_dataset) def test_confirmed_and_non_collaborative(self): self.prepare_data() datasets = self.export_dataset(confirmed_only=True) - expected_datasets = {self.project.admin.username: [{**self.data1, "bbox": [self.bbox1.to_dict()]}]} + expected_datasets = { + self.project.admin.username: [ + {**self.data1, "bbox": [self.bbox1.to_dict()], "Comments": [self.comment1.to_dict()]} + ] + } for username, dataset in expected_datasets.items(): self.assertEqual(datasets[username], dataset) @@ -547,6 +573,7 @@ def test_confirmed_and_collaborative(self): { **self.data1, "bbox": [self.bbox1.to_dict(), self.bbox2.to_dict()], + "Comments": [self.comment1.to_dict(), self.comment2.to_dict()], } ] self.assertEqual(dataset, expected_dataset) @@ -554,9 +581,11 @@ def test_confirmed_and_collaborative(self): class TestExportSegmentation(TestExport): def prepare_data(self, collaborative=False): - self.project = prepare_project(SEGMENTATION, collaborative_annotation=collaborative) + self.project = prepare_project(ProjectType.SEGMENTATION, collaborative_annotation=collaborative) self.example1 = mommy.make("ExportedExample", project=self.project.item, text="confirmed") self.example2 = mommy.make("ExportedExample", project=self.project.item, text="unconfirmed") + self.comment1 = mommy.make("ExportedComment", example=self.example1, user=self.project.admin) + self.comment2 = mommy.make("ExportedComment", example=self.example1, user=self.project.annotator) self.seg1 = mommy.make("ExportedSegmentation", example=self.example1, user=self.project.admin, points=[0, 1]) self.seg2 = mommy.make( "ExportedSegmentation", example=self.example1, user=self.project.annotator, points=[1, 2] @@ -571,22 +600,16 @@ def test_unconfirmed_and_non_collaborative(self): datasets = self.export_dataset() expected_datasets = { self.project.admin.username: [ - { - **self.data1, - self.column: [self.seg1.to_dict()], - }, - {**self.data2, self.column: []}, + {**self.data1, self.column: [self.seg1.to_dict()], "Comments": [self.comment1.to_dict()]}, + {**self.data2, self.column: [], "Comments": []}, ], self.project.approver.username: [ - {**self.data1, self.column: []}, - {**self.data2, self.column: []}, + {**self.data1, self.column: [], "Comments": []}, + {**self.data2, self.column: [], "Comments": []}, ], self.project.annotator.username: [ - { - **self.data1, - self.column: [self.seg2.to_dict()], - }, - {**self.data2, self.column: []}, + {**self.data1, self.column: [self.seg2.to_dict()], "Comments": [self.comment2.to_dict()]}, + {**self.data2, self.column: [], "Comments": []}, ], } for username, dataset in expected_datasets.items(): @@ -599,15 +622,20 @@ def test_unconfirmed_and_collaborative(self): { **self.data1, self.column: [self.seg1.to_dict(), self.seg2.to_dict()], + "Comments": [self.comment1.to_dict(), self.comment2.to_dict()], }, - {**self.data2, self.column: []}, + {**self.data2, self.column: [], "Comments": []}, ] self.assertEqual(dataset, expected_dataset) def test_confirmed_and_non_collaborative(self): self.prepare_data() datasets = self.export_dataset(confirmed_only=True) - expected_datasets = {self.project.admin.username: [{**self.data1, self.column: [self.seg1.to_dict()]}]} + expected_datasets = { + self.project.admin.username: [ + {**self.data1, self.column: [self.seg1.to_dict()], "Comments": [self.comment1.to_dict()]} + ] + } for username, dataset in expected_datasets.items(): self.assertEqual(datasets[username], dataset) @@ -618,6 +646,7 @@ def test_confirmed_and_collaborative(self): { **self.data1, self.column: [self.seg1.to_dict(), self.seg2.to_dict()], + "Comments": [self.comment1.to_dict(), self.comment2.to_dict()], } ] self.assertEqual(dataset, expected_dataset) @@ -625,9 +654,11 @@ def test_confirmed_and_collaborative(self): class TestExportImageCaptioning(TestExport): def prepare_data(self, collaborative=False): - self.project = prepare_project(IMAGE_CAPTIONING, collaborative_annotation=collaborative) + self.project = prepare_project(ProjectType.IMAGE_CAPTIONING, collaborative_annotation=collaborative) self.example1 = mommy.make("ExportedExample", project=self.project.item, text="confirmed") self.example2 = mommy.make("ExportedExample", project=self.project.item, text="unconfirmed") + self.comment1 = mommy.make("ExportedComment", example=self.example1, user=self.project.admin) + self.comment2 = mommy.make("ExportedComment", example=self.example1, user=self.project.annotator) self.text1 = mommy.make("TextLabel", example=self.example1, user=self.project.admin) self.text2 = mommy.make("TextLabel", example=self.example1, user=self.project.annotator) mommy.make("ExampleState", example=self.example1, confirmed_by=self.project.admin) @@ -640,16 +671,16 @@ def test_unconfirmed_and_non_collaborative(self): datasets = self.export_dataset() expected_datasets = { self.project.admin.username: [ - {**self.data1, self.column: [self.text1.text]}, - {**self.data2, self.column: []}, + {**self.data1, self.column: [self.text1.text], "Comments": [self.comment1.to_string()]}, + {**self.data2, self.column: [], "Comments": []}, ], self.project.approver.username: [ - {**self.data1, self.column: []}, - {**self.data2, self.column: []}, + {**self.data1, self.column: [], "Comments": []}, + {**self.data2, self.column: [], "Comments": []}, ], self.project.annotator.username: [ - {**self.data1, self.column: [self.text2.text]}, - {**self.data2, self.column: []}, + {**self.data1, self.column: [self.text2.text], "Comments": [self.comment2.to_string()]}, + {**self.data2, self.column: [], "Comments": []}, ], } for username, dataset in expected_datasets.items(): @@ -662,8 +693,9 @@ def test_unconfirmed_and_collaborative(self): { **self.data1, self.column: sorted([self.text1.text, self.text2.text]), + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), }, - {**self.data2, self.column: []}, + {**self.data2, self.column: [], "Comments": []}, ] self.assertEqual(dataset, expected_dataset) @@ -672,7 +704,7 @@ def test_confirmed_and_non_collaborative(self): datasets = self.export_dataset(confirmed_only=True) expected_datasets = { self.project.admin.username: [ - {**self.data1, self.column: [self.text1.text]}, + {**self.data1, self.column: [self.text1.text], "Comments": [self.comment1.to_string()]}, ], self.project.approver.username: [], self.project.annotator.username: [], @@ -687,6 +719,7 @@ def test_confirmed_and_collaborative(self): { **self.data1, self.column: sorted([self.text1.text, self.text2.text]), + "Comments": sorted([self.comment1.to_string(), self.comment2.to_string()]), } ] self.assertEqual(dataset, expected_dataset) @@ -694,7 +727,9 @@ def test_confirmed_and_collaborative(self): class TestExportRelation(TestExport): def prepare_data(self, collaborative=False): - self.project = prepare_project(SEQUENCE_LABELING, use_relation=True, collaborative_annotation=collaborative) + self.project = prepare_project( + ProjectType.SEQUENCE_LABELING, use_relation=True, collaborative_annotation=collaborative + ) self.example1 = mommy.make("ExportedExample", project=self.project.item, text="example") self.example2 = mommy.make("ExportedExample", project=self.project.item, text="unconfirmed") self.span1 = mommy.make( @@ -709,6 +744,8 @@ def prepare_data(self, collaborative=False): self.relation = mommy.make( "ExportedRelation", from_id=self.span1, to_id=self.span2, example=self.example1, user=self.project.admin ) + self.comment1 = mommy.make("ExportedComment", example=self.example1, user=self.project.admin) + self.comment2 = mommy.make("ExportedComment", example=self.example1, user=self.project.annotator) mommy.make("ExampleState", example=self.example1, confirmed_by=self.project.admin) self.data1 = self.data_to_text(self.example1) self.data2 = self.data_to_text(self.example2) @@ -722,20 +759,22 @@ def test_unconfirmed_and_non_collaborative(self): **self.data1, "entities": [self.span1.to_dict(), self.span2.to_dict()], "relations": [self.relation.to_dict()], + "Comments": [self.comment1.to_dict()], }, - {**self.data2, "entities": [], "relations": []}, + {**self.data2, "entities": [], "relations": [], "Comments": []}, ], self.project.annotator.username: [ { **self.data1, "entities": [self.span3.to_dict()], "relations": [], + "Comments": [self.comment2.to_dict()], }, - {**self.data2, "entities": [], "relations": []}, + {**self.data2, "entities": [], "relations": [], "Comments": []}, ], self.project.approver.username: [ - {**self.data1, "entities": [], "relations": []}, - {**self.data2, "entities": [], "relations": []}, + {**self.data1, "entities": [], "relations": [], "Comments": []}, + {**self.data2, "entities": [], "relations": [], "Comments": []}, ], } for username, dataset in expected_datasets.items(): @@ -749,8 +788,9 @@ def test_unconfirmed_and_collaborative(self): **self.data1, "entities": [self.span1.to_dict(), self.span2.to_dict(), self.span3.to_dict()], "relations": [self.relation.to_dict()], + "Comments": [self.comment1.to_dict(), self.comment2.to_dict()], }, - {**self.data2, "entities": [], "relations": []}, + {**self.data2, "entities": [], "relations": [], "Comments": []}, ] self.assertEqual(dataset, expected_dataset) @@ -763,6 +803,7 @@ def test_confirmed_and_non_collaborative(self): **self.data1, "entities": [self.span1.to_dict(), self.span2.to_dict()], "relations": [self.relation.to_dict()], + "Comments": [self.comment1.to_dict()], }, ], self.project.annotator.username: [], @@ -779,6 +820,7 @@ def test_confirmed_and_collaborative(self): **self.data1, "entities": [self.span1.to_dict(), self.span2.to_dict(), self.span3.to_dict()], "relations": [self.relation.to_dict()], + "Comments": [self.comment1.to_dict(), self.comment2.to_dict()], } ] self.assertEqual(dataset, expected_dataset) diff --git a/backend/data_export/tests/test_views.py b/backend/data_export/tests/test_views.py index ca3ad8a112..1ec814a0f3 100644 --- a/backend/data_export/tests/test_views.py +++ b/backend/data_export/tests/test_views.py @@ -2,13 +2,13 @@ from rest_framework.reverse import reverse from api.tests.utils import CRUDMixin -from projects.models import DOCUMENT_CLASSIFICATION +from projects.models import ProjectType from projects.tests.utils import prepare_project class TestDownloadCatalog(CRUDMixin): def setUp(self): - self.project = prepare_project(task=DOCUMENT_CLASSIFICATION) + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION) self.url = reverse(viewname="download-format", args=[self.project.item.id]) def test_allows_project_admin_to_list_catalog(self): diff --git a/backend/data_import/celery_tasks.py b/backend/data_import/celery_tasks.py index c51b755727..2fe09156ad 100644 --- a/backend/data_import/celery_tasks.py +++ b/backend/data_import/celery_tasks.py @@ -46,7 +46,7 @@ def check_uploaded_files(upload_ids: List[str], file_format: Format): return cleaned_ids, errors -@shared_task +@shared_task(autoretry_for=(Exception,), retry_backoff=True, retry_jitter=True) def import_dataset(user_id, project_id, file_format: str, upload_ids: List[str], task: str, **kwargs): project = get_object_or_404(Project, pk=project_id) user = get_object_or_404(get_user_model(), pk=user_id) diff --git a/backend/data_import/datasets.py b/backend/data_import/datasets.py index 473c00e610..cf0cc0bcae 100644 --- a/backend/data_import/datasets.py +++ b/backend/data_import/datasets.py @@ -20,18 +20,7 @@ Reader, ) from label_types.models import CategoryType, LabelType, RelationType, SpanType -from projects.models import ( - BOUNDING_BOX, - DOCUMENT_CLASSIFICATION, - IMAGE_CAPTIONING, - IMAGE_CLASSIFICATION, - INTENT_DETECTION_AND_SLOT_FILLING, - SEGMENTATION, - SEQ2SEQ, - SEQUENCE_LABELING, - SPEECH2TEXT, - Project, -) +from projects.models import Project, ProjectType class Dataset(abc.ABC): @@ -215,16 +204,16 @@ def errors(self) -> List[FileParseException]: def select_dataset(project: Project, task: str, file_format: Format) -> Type[Dataset]: mapping = { - DOCUMENT_CLASSIFICATION: TextClassificationDataset, - SEQUENCE_LABELING: SequenceLabelingDataset, + ProjectType.DOCUMENT_CLASSIFICATION: TextClassificationDataset, + ProjectType.SEQUENCE_LABELING: SequenceLabelingDataset, RELATION_EXTRACTION: RelationExtractionDataset, - SEQ2SEQ: Seq2seqDataset, - INTENT_DETECTION_AND_SLOT_FILLING: CategoryAndSpanDataset, - IMAGE_CLASSIFICATION: BinaryDataset, - IMAGE_CAPTIONING: BinaryDataset, - BOUNDING_BOX: BinaryDataset, - SEGMENTATION: BinaryDataset, - SPEECH2TEXT: BinaryDataset, + ProjectType.SEQ2SEQ: Seq2seqDataset, + ProjectType.INTENT_DETECTION_AND_SLOT_FILLING: CategoryAndSpanDataset, + ProjectType.IMAGE_CLASSIFICATION: BinaryDataset, + ProjectType.IMAGE_CAPTIONING: BinaryDataset, + ProjectType.BOUNDING_BOX: BinaryDataset, + ProjectType.SEGMENTATION: BinaryDataset, + ProjectType.SPEECH2TEXT: BinaryDataset, } if task not in mapping: task = project.project_type diff --git a/backend/data_import/pipeline/catalog.py b/backend/data_import/pipeline/catalog.py index af2e2c42e2..6acc794fe5 100644 --- a/backend/data_import/pipeline/catalog.py +++ b/backend/data_import/pipeline/catalog.py @@ -7,17 +7,7 @@ from typing_extensions import Literal from .exceptions import FileFormatException -from projects.models import ( - BOUNDING_BOX, - DOCUMENT_CLASSIFICATION, - IMAGE_CAPTIONING, - IMAGE_CLASSIFICATION, - INTENT_DETECTION_AND_SLOT_FILLING, - SEGMENTATION, - SEQ2SEQ, - SEQUENCE_LABELING, - SPEECH2TEXT, -) +from projects.models import ProjectType # Define the example directories EXAMPLE_DIR = Path(__file__).parent.resolve() / "examples" @@ -287,7 +277,12 @@ def register(cls, option: Option): # Text tasks -text_tasks = [DOCUMENT_CLASSIFICATION, SEQUENCE_LABELING, SEQ2SEQ, INTENT_DETECTION_AND_SLOT_FILLING] +text_tasks = [ + ProjectType.DOCUMENT_CLASSIFICATION, + ProjectType.SEQUENCE_LABELING, + ProjectType.SEQ2SEQ, + ProjectType.INTENT_DETECTION_AND_SLOT_FILLING, +] for task_id in text_tasks: Options.register( Option( @@ -312,7 +307,7 @@ def register(cls, option: Option): Options.register( Option( display_name=CSV.name, - task_id=DOCUMENT_CLASSIFICATION, + task_id=ProjectType.DOCUMENT_CLASSIFICATION, file_format=CSV, arg=ArgDelimiter, file=TEXT_CLASSIFICATION_DIR / "example.csv", @@ -321,7 +316,7 @@ def register(cls, option: Option): Options.register( Option( display_name=FastText.name, - task_id=DOCUMENT_CLASSIFICATION, + task_id=ProjectType.DOCUMENT_CLASSIFICATION, file_format=FastText, arg=ArgEncoding, file=TEXT_CLASSIFICATION_DIR / "example.txt", @@ -330,7 +325,7 @@ def register(cls, option: Option): Options.register( Option( display_name=JSON.name, - task_id=DOCUMENT_CLASSIFICATION, + task_id=ProjectType.DOCUMENT_CLASSIFICATION, file_format=JSON, arg=ArgColumn, file=TEXT_CLASSIFICATION_DIR / "example.json", @@ -339,7 +334,7 @@ def register(cls, option: Option): Options.register( Option( display_name=JSONL.name, - task_id=DOCUMENT_CLASSIFICATION, + task_id=ProjectType.DOCUMENT_CLASSIFICATION, file_format=JSONL, arg=ArgColumn, file=TEXT_CLASSIFICATION_DIR / "example.jsonl", @@ -348,7 +343,7 @@ def register(cls, option: Option): Options.register( Option( display_name=Excel.name, - task_id=DOCUMENT_CLASSIFICATION, + task_id=ProjectType.DOCUMENT_CLASSIFICATION, file_format=Excel, arg=ArgColumn, file=TEXT_CLASSIFICATION_DIR / "example.csv", @@ -359,7 +354,7 @@ def register(cls, option: Option): Options.register( Option( display_name=JSONL.name, - task_id=SEQUENCE_LABELING, + task_id=ProjectType.SEQUENCE_LABELING, file_format=JSONL, arg=ArgColumn, file=SEQUENCE_LABELING_DIR / "example.jsonl", @@ -368,7 +363,7 @@ def register(cls, option: Option): Options.register( Option( display_name=CoNLL.name, - task_id=SEQUENCE_LABELING, + task_id=ProjectType.SEQUENCE_LABELING, file_format=CoNLL, arg=ArgCoNLL, file=SEQUENCE_LABELING_DIR / "example.txt", @@ -390,7 +385,7 @@ def register(cls, option: Option): Options.register( Option( display_name=CSV.name, - task_id=SEQ2SEQ, + task_id=ProjectType.SEQ2SEQ, file_format=CSV, arg=ArgDelimiter, file=SEQ2SEQ_DIR / "example.csv", @@ -399,7 +394,7 @@ def register(cls, option: Option): Options.register( Option( display_name=JSON.name, - task_id=SEQ2SEQ, + task_id=ProjectType.SEQ2SEQ, file_format=JSON, arg=ArgColumn, file=SEQ2SEQ_DIR / "example.json", @@ -408,7 +403,7 @@ def register(cls, option: Option): Options.register( Option( display_name=JSONL.name, - task_id=SEQ2SEQ, + task_id=ProjectType.SEQ2SEQ, file_format=JSONL, arg=ArgColumn, file=SEQ2SEQ_DIR / "example.jsonl", @@ -417,7 +412,7 @@ def register(cls, option: Option): Options.register( Option( display_name=Excel.name, - task_id=SEQ2SEQ, + task_id=ProjectType.SEQ2SEQ, file_format=Excel, arg=ArgColumn, file=SEQ2SEQ_DIR / "example.csv", @@ -428,7 +423,7 @@ def register(cls, option: Option): Options.register( Option( display_name=JSONL.name, - task_id=INTENT_DETECTION_AND_SLOT_FILLING, + task_id=ProjectType.INTENT_DETECTION_AND_SLOT_FILLING, file_format=JSONL, arg=ArgNone, file=INTENT_DETECTION_DIR / "example.jsonl", @@ -436,7 +431,12 @@ def register(cls, option: Option): ) # Image tasks -image_tasks = [IMAGE_CLASSIFICATION, IMAGE_CAPTIONING, BOUNDING_BOX, SEGMENTATION] +image_tasks = [ + ProjectType.IMAGE_CLASSIFICATION, + ProjectType.IMAGE_CAPTIONING, + ProjectType.BOUNDING_BOX, + ProjectType.SEGMENTATION, +] for task_name in image_tasks: Options.register( Option( @@ -452,7 +452,7 @@ def register(cls, option: Option): Options.register( Option( display_name=AudioFile.name, - task_id=SPEECH2TEXT, + task_id=ProjectType.SPEECH2TEXT, file_format=AudioFile, arg=ArgNone, file=SPEECH_TO_TEXT_DIR / "audio_files.txt", diff --git a/backend/data_import/pipeline/examples/relation_extraction/example.jsonl b/backend/data_import/pipeline/examples/relation_extraction/example.jsonl index 6ba958ff58..2f6dcf277e 100644 --- a/backend/data_import/pipeline/examples/relation_extraction/example.jsonl +++ b/backend/data_import/pipeline/examples/relation_extraction/example.jsonl @@ -1,46 +1 @@ -{ - "text": "Google was founded on September 4, 1998, by Larry Page and Sergey Brin.", - "entities": [ - { - "id": 0, - "start_offset": 0, - "end_offset": 6, - "label": "ORG" - }, - { - "id": 1, - "start_offset": 22, - "end_offset": 39, - "label": "DATE" - }, - { - "id": 2, - "start_offset": 44, - "end_offset": 54, - "label": "PERSON" - }, - { - "id": 3, - "start_offset": 59, - "end_offset": 70, - "label": "PERSON" - } - ], - "relations": [ - { - "from_id": 0, - "to_id": 1, - "type": "foundedAt" - }, - { - "from_id": 0, - "to_id": 2, - "type": "foundedBy" - }, - { - "from_id": 0, - "to_id": 3, - "type": "foundedBy" - } - ] -} +{"text":"Google was founded on September 4, 1998, by Larry Page and Sergey Brin.","entities":[{"id":0,"start_offset":0,"end_offset":6,"label":"ORG"},{"id":1,"start_offset":22,"end_offset":39,"label":"DATE"},{"id":2,"start_offset":44,"end_offset":54,"label":"PERSON"},{"id":3,"start_offset":59,"end_offset":70,"label":"PERSON"}],"relations":[{"from_id":0,"to_id":1,"type":"foundedAt"},{"from_id":0,"to_id":2,"type":"foundedBy"},{"from_id":0,"to_id":3,"type":"foundedBy"}]} \ No newline at end of file diff --git a/backend/data_import/pipeline/label.py b/backend/data_import/pipeline/label.py index bdff2d4389..82efa2a1f1 100644 --- a/backend/data_import/pipeline/label.py +++ b/backend/data_import/pipeline/label.py @@ -2,7 +2,7 @@ import uuid from typing import Any, Optional -from pydantic import UUID4, BaseModel, ConstrainedStr, NonNegativeInt, root_validator +from pydantic import UUID4, BaseModel, NonNegativeInt, constr, root_validator from .label_types import LabelTypes from examples.models import Example @@ -15,10 +15,6 @@ from projects.models import Project -class NonEmptyStr(ConstrainedStr): - min_length = 1 - - class Label(BaseModel, abc.ABC): id: int = -1 uuid: UUID4 @@ -30,7 +26,7 @@ def __init__(self, **data): @abc.abstractmethod def __lt__(self, other): - raise NotImplementedError() + return NotImplemented @classmethod def parse(cls, example_uuid: UUID4, obj: Any): @@ -49,14 +45,14 @@ def __hash__(self): class CategoryLabel(Label): - label: NonEmptyStr + label: constr(min_length=1) # type: ignore def __lt__(self, other): return self.label < other.label @classmethod def parse(cls, example_uuid: UUID4, obj: Any): - return cls(example_uuid=example_uuid, label=obj) + return cls(example_uuid=example_uuid, label=obj) # type: ignore def create_type(self, project: Project) -> Optional[LabelType]: return CategoryType(text=self.label, project=project) @@ -66,14 +62,14 @@ def create(self, user, example: Example, types: LabelTypes, **kwargs): class SpanLabel(Label): - label: NonEmptyStr + label: constr(min_length=1) # type: ignore start_offset: NonNegativeInt end_offset: NonNegativeInt def __lt__(self, other): return self.start_offset < other.start_offset - @root_validator + @root_validator(skip_on_failure=True) def check_start_offset_is_less_than_end_offset(cls, values): start_offset, end_offset = values.get("start_offset"), values.get("end_offset") if start_offset >= end_offset: @@ -105,14 +101,14 @@ def create(self, user, example: Example, types: LabelTypes, **kwargs): class TextLabel(Label): - text: NonEmptyStr + text: constr(min_length=1) # type: ignore def __lt__(self, other): return self.text < other.text @classmethod def parse(cls, example_uuid: UUID4, obj: Any): - return cls(example_uuid=example_uuid, text=obj) + return cls(example_uuid=example_uuid, text=obj) # type: ignore def create_type(self, project: Project) -> Optional[LabelType]: return None @@ -124,7 +120,7 @@ def create(self, user, example: Example, types: LabelTypes, **kwargs): class RelationLabel(Label): from_id: int to_id: int - type: NonEmptyStr + type: constr(min_length=1) # type: ignore def __lt__(self, other): return self.from_id < other.from_id @@ -142,6 +138,6 @@ def create(self, user, example: Example, types: LabelTypes, **kwargs): user=user, example=example, type=types[self.type], - from_id=kwargs["id_to_span"][self.from_id], - to_id=kwargs["id_to_span"][self.to_id], + from_id=kwargs["id_to_span"][(self.from_id, str(self.example_uuid))], + to_id=kwargs["id_to_span"][(self.to_id, str(self.example_uuid))], ) diff --git a/backend/data_import/pipeline/labels.py b/backend/data_import/pipeline/labels.py index 97045526c9..524bf36f1a 100644 --- a/backend/data_import/pipeline/labels.py +++ b/backend/data_import/pipeline/labels.py @@ -1,6 +1,6 @@ import abc from itertools import groupby -from typing import Dict, List +from typing import Dict, List, Tuple from .examples import Examples from .label import Label @@ -70,11 +70,11 @@ def clean(self, project: Project): self.labels = spans @property - def id_to_span(self) -> Dict[int, SpanModel]: - span_uuids = [str(label.uuid) for label in self.labels] - spans = SpanModel.objects.filter(uuid__in=span_uuids) + def id_to_span(self) -> Dict[Tuple[int, str], SpanModel]: + uuids = [str(span.uuid) for span in self.labels] + spans = SpanModel.objects.filter(uuid__in=uuids) uuid_to_span = {span.uuid: span for span in spans} - return {span.id: uuid_to_span[span.uuid] for span in self.labels} + return {(span.id, str(span.example_uuid)): uuid_to_span[span.uuid] for span in self.labels} class Texts(Labels): diff --git a/backend/data_import/tests/test_catalog.py b/backend/data_import/tests/test_catalog.py index e702cd81aa..dc10e61504 100644 --- a/backend/data_import/tests/test_catalog.py +++ b/backend/data_import/tests/test_catalog.py @@ -1,27 +1,12 @@ import unittest from data_import.pipeline.catalog import Options -from projects.models import ( - DOCUMENT_CLASSIFICATION, - IMAGE_CLASSIFICATION, - INTENT_DETECTION_AND_SLOT_FILLING, - SEQ2SEQ, - SEQUENCE_LABELING, - SPEECH2TEXT, -) +from projects.models import ProjectType class TestOptions(unittest.TestCase): def test_return_at_least_one_option(self): - tasks = [ - DOCUMENT_CLASSIFICATION, - IMAGE_CLASSIFICATION, - INTENT_DETECTION_AND_SLOT_FILLING, - SEQ2SEQ, - SEQUENCE_LABELING, - SPEECH2TEXT, - ] - for task in tasks: + for task in ProjectType: with self.subTest(task=task): options = Options.filter_by_task(task) self.assertGreaterEqual(len(options), 1) diff --git a/backend/data_import/tests/test_examples.py b/backend/data_import/tests/test_examples.py index 4ce574d374..d356c41463 100644 --- a/backend/data_import/tests/test_examples.py +++ b/backend/data_import/tests/test_examples.py @@ -4,13 +4,13 @@ from data_import.pipeline.examples import Examples from examples.models import Example -from projects.models import DOCUMENT_CLASSIFICATION +from projects.models import ProjectType from projects.tests.utils import prepare_project class TestExamples(TestCase): def setUp(self): - self.project = prepare_project(DOCUMENT_CLASSIFICATION) + self.project = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION) self.example_uuid = uuid.uuid4() example = Example(uuid=self.example_uuid, text="A", project=self.project.item) self.examples = Examples([example]) diff --git a/backend/data_import/tests/test_label.py b/backend/data_import/tests/test_label.py index da79ca49f3..3717dc91d0 100644 --- a/backend/data_import/tests/test_label.py +++ b/backend/data_import/tests/test_label.py @@ -15,7 +15,7 @@ from labels.models import Relation as RelationModel from labels.models import Span as SpanModel from labels.models import TextLabel as TextModel -from projects.models import DOCUMENT_CLASSIFICATION, SEQ2SEQ, SEQUENCE_LABELING +from projects.models import ProjectType from projects.tests.utils import prepare_project @@ -25,11 +25,11 @@ class TestLabel(TestCase): def setUp(self): self.project = prepare_project(self.task) self.user = self.project.admin - self.example = mommy.make("Example", project=self.project.item) + self.example = mommy.make("Example", project=self.project.item, text="hello world") class TestCategoryLabel(TestLabel): - task = DOCUMENT_CLASSIFICATION + task = ProjectType.DOCUMENT_CLASSIFICATION def test_comparison(self): category1 = CategoryLabel(label="A", example_uuid=uuid.uuid4()) @@ -61,7 +61,7 @@ def test_create(self): class TestSpanLabel(TestLabel): - task = SEQUENCE_LABELING + task = ProjectType.SEQUENCE_LABELING def test_comparison(self): span1 = SpanLabel(label="A", start_offset=0, end_offset=1, example_uuid=uuid.uuid4()) @@ -110,7 +110,7 @@ def test_create(self): class TestTextLabel(TestLabel): - task = SEQ2SEQ + task = ProjectType.SEQ2SEQ def test_comparison(self): text1 = TextLabel(text="A", example_uuid=uuid.uuid4()) @@ -140,7 +140,7 @@ def test_create(self): class TestRelationLabel(TestLabel): - task = SEQUENCE_LABELING + task = ProjectType.SEQUENCE_LABELING def test_comparison(self): relation1 = RelationLabel(type="A", from_id=0, to_id=1, example_uuid=uuid.uuid4()) @@ -166,12 +166,12 @@ def test_create_type(self): self.assertEqual(relation_type.text, "A") def test_create(self): - relation = RelationLabel(type="A", from_id=0, to_id=1, example_uuid=uuid.uuid4()) + relation = RelationLabel(type="A", from_id=0, to_id=1, example_uuid=self.example.uuid) types = MagicMock() types.__getitem__.return_value = mommy.make(RelationType, project=self.project.item) id_to_span = { - 0: mommy.make(SpanModel, start_offset=0, end_offset=1), - 1: mommy.make(SpanModel, start_offset=2, end_offset=3), + (0, str(self.example.uuid)): mommy.make(SpanModel, start_offset=0, end_offset=1, example=self.example), + (1, str(self.example.uuid)): mommy.make(SpanModel, start_offset=2, end_offset=3, example=self.example), } relation_model = relation.create(self.user, self.example, types, id_to_span=id_to_span) self.assertIsInstance(relation_model, RelationModel) diff --git a/backend/data_import/tests/test_label_types.py b/backend/data_import/tests/test_label_types.py index d1195fdfac..af0a853583 100644 --- a/backend/data_import/tests/test_label_types.py +++ b/backend/data_import/tests/test_label_types.py @@ -3,13 +3,13 @@ from data_import.pipeline.label_types import LabelTypes from label_types.models import CategoryType -from projects.models import DOCUMENT_CLASSIFICATION +from projects.models import ProjectType from projects.tests.utils import prepare_project class TestCategoryLabel(TestCase): def setUp(self): - self.project = prepare_project(DOCUMENT_CLASSIFICATION) + self.project = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION) self.user = self.project.admin self.example = mommy.make("Example", project=self.project.item) diff --git a/backend/data_import/tests/test_labels.py b/backend/data_import/tests/test_labels.py index 6b3a27eabb..1d39805256 100644 --- a/backend/data_import/tests/test_labels.py +++ b/backend/data_import/tests/test_labels.py @@ -16,14 +16,14 @@ from label_types.models import CategoryType, RelationType, SpanType from labels.models import Category, Relation, Span from labels.models import TextLabel as TextLabelModel -from projects.models import DOCUMENT_CLASSIFICATION, SEQUENCE_LABELING +from projects.models import ProjectType from projects.tests.utils import prepare_project class TestCategories(TestCase): def setUp(self): self.types = LabelTypes(CategoryType) - self.project = prepare_project(DOCUMENT_CLASSIFICATION) + self.project = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION) self.user = self.project.admin example_uuid = uuid.uuid4() labels = [ @@ -59,7 +59,7 @@ def test_save_types(self): class TestSpans(TestCase): def setUp(self): self.types = LabelTypes(SpanType) - self.project = prepare_project(SEQUENCE_LABELING, allow_overlapping=True) + self.project = prepare_project(ProjectType.SEQUENCE_LABELING, allow_overlapping=True) self.user = self.project.admin example_uuid = uuid.uuid4() labels = [ @@ -113,7 +113,7 @@ def test_save_types(self): class TestTexts(TestCase): def setUp(self): self.types = LabelTypes(DummyLabelType) - self.project = prepare_project(SEQUENCE_LABELING) + self.project = prepare_project(ProjectType.SEQUENCE_LABELING) self.user = self.project.admin example_uuid = uuid.uuid4() labels = [ @@ -143,10 +143,10 @@ def test_save_types(self): class TestRelations(TestCase): def setUp(self): self.types = LabelTypes(RelationType) - self.project = prepare_project(SEQUENCE_LABELING, use_relation=True) + self.project = prepare_project(ProjectType.SEQUENCE_LABELING, use_relation=True) self.user = self.project.admin example_uuid = uuid.uuid4() - example = mommy.make("Example", project=self.project.item, uuid=example_uuid) + example = mommy.make("Example", project=self.project.item, uuid=example_uuid, text="hello world") from_span = mommy.make("Span", example=example, start_offset=0, end_offset=1) to_span = mommy.make("Span", example=example, start_offset=2, end_offset=3) labels = [ @@ -154,7 +154,7 @@ def setUp(self): ] self.relations = Relations(labels, self.types) self.spans = MagicMock() - self.spans.id_to_span = {from_span.id: from_span, to_span.id: to_span} + self.spans.id_to_span = {(from_span.id, str(example_uuid)): from_span, (to_span.id, str(example_uuid)): to_span} self.examples = MagicMock() self.examples.__getitem__.return_value = example self.examples.__contains__.return_value = True diff --git a/backend/data_import/tests/test_tasks.py b/backend/data_import/tests/test_tasks.py index d66969162c..e3c98cb5a3 100644 --- a/backend/data_import/tests/test_tasks.py +++ b/backend/data_import/tests/test_tasks.py @@ -12,13 +12,7 @@ from examples.models import Example from label_types.models import SpanType from labels.models import Category, Span -from projects.models import ( - DOCUMENT_CLASSIFICATION, - IMAGE_CLASSIFICATION, - INTENT_DETECTION_AND_SLOT_FILLING, - SEQ2SEQ, - SEQUENCE_LABELING, -) +from projects.models import ProjectType from projects.tests.utils import prepare_project @@ -57,7 +51,7 @@ def import_dataset(self, filename, file_format, task, kwargs=None): @override_settings(MAX_UPLOAD_SIZE=0) class TestMaxFileSize(TestImportData): - task = DOCUMENT_CLASSIFICATION + task = ProjectType.DOCUMENT_CLASSIFICATION def test_jsonl(self): filename = "text_classification/example.jsonl" @@ -69,7 +63,7 @@ def test_jsonl(self): class TestInvalidFileFormat(TestImportData): - task = DOCUMENT_CLASSIFICATION + task = ProjectType.DOCUMENT_CLASSIFICATION def test_invalid_file_format(self): filename = "text_classification/example.csv" @@ -79,7 +73,7 @@ def test_invalid_file_format(self): class TestImportClassificationData(TestImportData): - task = DOCUMENT_CLASSIFICATION + task = ProjectType.DOCUMENT_CLASSIFICATION def assert_examples(self, dataset): with self.subTest(): @@ -180,7 +174,7 @@ def test_wrong_csv(self): class TestImportSequenceLabelingData(TestImportData): - task = SEQUENCE_LABELING + task = ProjectType.SEQUENCE_LABELING def assert_examples(self, dataset): self.assertEqual(Example.objects.count(), len(dataset)) @@ -223,7 +217,7 @@ def test_jsonl_with_overlapping(self): class TestImportRelationExtractionData(TestImportData): - task = SEQUENCE_LABELING + task = ProjectType.SEQUENCE_LABELING def setUp(self): self.project = prepare_project(self.task, use_relation=True) @@ -259,7 +253,7 @@ def test_jsonl(self): class TestImportSeq2seqData(TestImportData): - task = SEQ2SEQ + task = ProjectType.SEQ2SEQ def assert_examples(self, dataset): self.assertEqual(Example.objects.count(), len(dataset)) @@ -291,7 +285,7 @@ def test_csv(self): class TestImportIntentDetectionAndSlotFillingData(TestImportData): - task = INTENT_DETECTION_AND_SLOT_FILLING + task = ProjectType.INTENT_DETECTION_AND_SLOT_FILLING def assert_examples(self, dataset): self.assertEqual(Example.objects.count(), len(dataset)) @@ -316,7 +310,7 @@ def test_entities_and_cats(self): class TestImportImageClassificationData(TestImportData): - task = IMAGE_CLASSIFICATION + task = ProjectType.IMAGE_CLASSIFICATION def test_example(self): filename = "images/1500x500.jpeg" @@ -327,7 +321,7 @@ def test_example(self): @override_settings(ENABLE_FILE_TYPE_CHECK=True) class TestFileTypeChecking(TestImportData): - task = IMAGE_CLASSIFICATION + task = ProjectType.IMAGE_CLASSIFICATION def test_example(self): filename = "images/example.ico" diff --git a/backend/data_import/tests/test_views.py b/backend/data_import/tests/test_views.py index d0f49912c6..0b00b9b543 100644 --- a/backend/data_import/tests/test_views.py +++ b/backend/data_import/tests/test_views.py @@ -2,13 +2,13 @@ from rest_framework.reverse import reverse from api.tests.utils import CRUDMixin -from projects.models import DOCUMENT_CLASSIFICATION +from projects.models import ProjectType from projects.tests.utils import prepare_project class TestImportCatalog(CRUDMixin): def setUp(self): - self.project = prepare_project(task=DOCUMENT_CLASSIFICATION) + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION) self.url = reverse(viewname="catalog", args=[self.project.item.id]) def test_allows_project_admin_to_list_catalog(self): diff --git a/frontend/services/application/metrics/metricsData.ts b/backend/examples/assignment/__init__.py similarity index 100% rename from frontend/services/application/metrics/metricsData.ts rename to backend/examples/assignment/__init__.py diff --git a/backend/examples/assignment/strategies.py b/backend/examples/assignment/strategies.py new file mode 100644 index 0000000000..11e76efaa6 --- /dev/null +++ b/backend/examples/assignment/strategies.py @@ -0,0 +1,81 @@ +import abc +import dataclasses +import enum +import random +from typing import List + +import numpy as np + + +@dataclasses.dataclass +class Assignment: + user: int + example: int + + +class StrategyName(enum.Enum): + weighted_sequential = enum.auto() + weighted_random = enum.auto() + sampling_without_replacement = enum.auto() + + +def create_assignment_strategy(strategy_name: StrategyName, dataset_size: int, weights: List[int]) -> "BaseStrategy": + if strategy_name == StrategyName.weighted_sequential: + return WeightedSequentialStrategy(dataset_size, weights) + elif strategy_name == StrategyName.weighted_random: + return WeightedRandomStrategy(dataset_size, weights) + elif strategy_name == StrategyName.sampling_without_replacement: + return SamplingWithoutReplacementStrategy(dataset_size, weights) + else: + raise ValueError(f"Unknown strategy name: {strategy_name}") + + +class BaseStrategy(abc.ABC): + @abc.abstractmethod + def assign(self) -> List[Assignment]: ... + + +class WeightedSequentialStrategy(BaseStrategy): + def __init__(self, dataset_size: int, weights: List[int]): + if sum(weights) != 100: + raise ValueError("Sum of weights must be 100") + self.dataset_size = dataset_size + self.weights = weights + + def assign(self) -> List[Assignment]: + assignments = [] + cumsum = np.cumsum([0] + self.weights) + ratio = np.round(cumsum / 100 * self.dataset_size).astype(int) + for user, (start, end) in enumerate(zip(ratio, ratio[1:])): # Todo: use itertools.pairwise + assignments.extend([Assignment(user=user, example=example) for example in range(start, end)]) + return assignments + + +class WeightedRandomStrategy(BaseStrategy): + def __init__(self, dataset_size: int, weights: List[int]): + if sum(weights) != 100: + raise ValueError("Sum of weights must be 100") + self.dataset_size = dataset_size + self.weights = weights + + def assign(self) -> List[Assignment]: + proba = np.array(self.weights) / 100 + assignees = np.random.choice(range(len(self.weights)), size=self.dataset_size, p=proba) + return [Assignment(user=user, example=example) for example, user in enumerate(assignees)] + + +class SamplingWithoutReplacementStrategy(BaseStrategy): + def __init__(self, dataset_size: int, weights: List[int]): + if not (0 <= sum(weights) <= 100 * len(weights)): + raise ValueError("Sum of weights must be between 0 and 100 x number of members") + self.dataset_size = dataset_size + self.weights = weights + + def assign(self) -> List[Assignment]: + assignments = [] + proba = np.array(self.weights) / 100 + for user, p in enumerate(proba): + count = int(self.dataset_size * p) + examples = random.sample(range(self.dataset_size), count) + assignments.extend([Assignment(user=user, example=example) for example in examples]) + return assignments diff --git a/backend/examples/assignment/usecase.py b/backend/examples/assignment/usecase.py new file mode 100644 index 0000000000..f16949ea31 --- /dev/null +++ b/backend/examples/assignment/usecase.py @@ -0,0 +1,33 @@ +from typing import List + +from django.shortcuts import get_object_or_404 + +from examples.assignment.strategies import StrategyName, create_assignment_strategy +from examples.models import Assignment, Example +from projects.models import Member, Project + + +def bulk_assign(project_id: int, strategy_name: StrategyName, member_ids: List[int], weights: List[int]) -> None: + project = get_object_or_404(Project, pk=project_id) + members = Member.objects.filter(project=project, pk__in=member_ids) + if len(members) != len(member_ids): + raise ValueError("Invalid member ids") + # Sort members by member_ids + members = sorted(members, key=lambda m: member_ids.index(m.id)) + index_to_user = {i: member.user for i, member in enumerate(members)} + + unassigned_examples = Example.objects.filter(project=project, assignments__isnull=True) + index_to_example = {i: example for i, example in enumerate(unassigned_examples)} + dataset_size = unassigned_examples.count() + + strategy = create_assignment_strategy(strategy_name, dataset_size, weights) + assignments = strategy.assign() + assignments = [ + Assignment( + project=project, + example=index_to_example[assignment.example], + assignee=index_to_user[assignment.user], + ) + for assignment in assignments + ] + Assignment.objects.bulk_create(assignments) diff --git a/backend/examples/assignment/workload.py b/backend/examples/assignment/workload.py new file mode 100644 index 0000000000..26eb6a042d --- /dev/null +++ b/backend/examples/assignment/workload.py @@ -0,0 +1,20 @@ +from typing import List + +from pydantic import BaseModel, NonNegativeInt + + +class Workload(BaseModel): + weight: NonNegativeInt + member_id: int + + +class WorkloadAllocation(BaseModel): + workloads: List[Workload] + + @property + def member_ids(self) -> List[int]: + return [w.member_id for w in self.workloads] + + @property + def weights(self) -> List[int]: + return [w.weight for w in self.workloads] diff --git a/backend/examples/filters.py b/backend/examples/filters.py index fceaba1264..6b66ecb903 100644 --- a/backend/examples/filters.py +++ b/backend/examples/filters.py @@ -1,11 +1,13 @@ -from django.db.models import Count, Q -from django_filters.rest_framework import BooleanFilter, FilterSet +from django.db.models import Count, Q, QuerySet +from django_filters.rest_framework import BooleanFilter, CharFilter, FilterSet from .models import Example class ExampleFilter(FilterSet): confirmed = BooleanFilter(field_name="states", method="filter_by_state") + label = CharFilter(method="filter_by_label") + assignee = CharFilter(method="filter_by_assignee") def filter_by_state(self, queryset, field_name, is_confirmed: bool): queryset = queryset.annotate( @@ -21,6 +23,38 @@ def filter_by_state(self, queryset, field_name, is_confirmed: bool): queryset = queryset.filter(num_confirm__lte=0) return queryset + def filter_by_label(self, queryset: QuerySet, field_name: str, label: str) -> QuerySet: + """Filter examples by a given label name. + + This performs filtering on all of the following labels at once: + - categories + - spans + - relations + - bboxes + - segmentations + + Todo: Consider project type to make filtering more efficient. + + Args: + queryset (QuerySet): QuerySet to filter. + field_name (str): This equals to `label`. + label (str): The label name to filter. + + Returns: + QuerySet: Filtered examples. + """ + queryset = queryset.filter( + Q(categories__label__text=label) + | Q(spans__label__text=label) + | Q(relations__type__text=label) + | Q(bboxes__label__text=label) + | Q(segmentations__label__text=label) + ) + return queryset + + def filter_by_assignee(self, queryset: QuerySet, field_name: str, assignee: str) -> QuerySet: + return queryset.filter(assignments__assignee__username=assignee) + class Meta: model = Example - fields = ("project", "text", "created_at", "updated_at") + fields = ("project", "text", "created_at", "updated_at", "label", "assignee") diff --git a/backend/examples/migrations/0007_example_score.py b/backend/examples/migrations/0007_example_score.py new file mode 100644 index 0000000000..a8f6afdc0f --- /dev/null +++ b/backend/examples/migrations/0007_example_score.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.7 on 2022-10-21 07:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("examples", "0006_alter_example_upload_name"), + ] + + operations = [ + migrations.AddField( + model_name="example", + name="score", + field=models.FloatField(default=100), + ), + ] diff --git a/backend/examples/migrations/0008_assignment.py b/backend/examples/migrations/0008_assignment.py new file mode 100644 index 0000000000..ef0ee15127 --- /dev/null +++ b/backend/examples/migrations/0008_assignment.py @@ -0,0 +1,45 @@ +# Generated by Django 4.1.10 on 2023-07-24 05:39 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ("projects", "0008_project_allow_member_to_create_label_type_and_more"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("examples", "0007_example_score"), + ] + + operations = [ + migrations.CreateModel( + name="Assignment", + fields=[ + ("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ("created_at", models.DateTimeField(auto_now_add=True, db_index=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "assignee", + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ( + "example", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="assignments", to="examples.example" + ), + ), + ( + "project", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="assignments", to="projects.project" + ), + ), + ], + options={ + "unique_together": {("example", "assignee")}, + }, + ), + ] diff --git a/backend/examples/models.py b/backend/examples/models.py index 51465fc5cd..b7fa2e0914 100644 --- a/backend/examples/models.py +++ b/backend/examples/models.py @@ -1,6 +1,7 @@ import uuid from django.contrib.auth.models import User +from django.core.exceptions import ValidationError from django.db import models from django_drf_filepond.models import DrfFilePondStoredStorage @@ -18,6 +19,7 @@ class Example(models.Model): project = models.ForeignKey(to=Project, on_delete=models.CASCADE, related_name="examples") annotations_approved_by = models.ForeignKey(to=User, on_delete=models.SET_NULL, null=True, blank=True) text = models.TextField(null=True, blank=True) + score = models.FloatField(default=100) created_at = models.DateTimeField(auto_now_add=True, db_index=True) updated_at = models.DateTimeField(auto_now=True) @@ -36,6 +38,29 @@ class Meta: ordering = ["created_at"] +class Assignment(models.Model): + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + project = models.ForeignKey(to=Project, on_delete=models.CASCADE, related_name="assignments") + example = models.ForeignKey(to=Example, on_delete=models.CASCADE, related_name="assignments") + assignee = models.ForeignKey(to=User, on_delete=models.CASCADE) + created_at = models.DateTimeField(auto_now_add=True, db_index=True) + updated_at = models.DateTimeField(auto_now=True) + + class Meta: + unique_together = (("example", "assignee"),) + + def clean(self): + # assignee must be a member of the project + if not self.project.members.filter(id=self.assignee.id).exists(): + raise ValidationError("Assignee must be a member of the project") + + # example must be in the project + if not self.project.examples.filter(id=self.example.id).exists(): + raise ValidationError("Example must be in the project") + + return super().clean() + + class ExampleState(models.Model): objects = ExampleStateManager() example = models.ForeignKey(to=Example, on_delete=models.CASCADE, related_name="states") diff --git a/backend/examples/serializers.py b/backend/examples/serializers.py index fad6690ea6..4ea517feeb 100644 --- a/backend/examples/serializers.py +++ b/backend/examples/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from .models import Comment, Example, ExampleState +from .models import Assignment, Comment, Example, ExampleState class CommentSerializer(serializers.ModelSerializer): @@ -17,9 +17,17 @@ class Meta: read_only_fields = ("user", "example") +class AssignmentSerializer(serializers.ModelSerializer): + class Meta: + model = Assignment + fields = ("id", "assignee", "example", "created_at", "updated_at") + read_only_fields = ("id", "created_at", "updated_at") + + class ExampleSerializer(serializers.ModelSerializer): annotation_approver = serializers.SerializerMethodField() is_confirmed = serializers.SerializerMethodField() + assignments = serializers.SerializerMethodField() @classmethod def get_annotation_approver(cls, instance): @@ -34,6 +42,16 @@ def get_is_confirmed(self, instance): states = instance.states.filter(confirmed_by_id=user.id) return states.count() > 0 + def get_assignments(self, instance): + return [ + { + "id": assignment.id, + "assignee": assignment.assignee.username, + "assignee_id": assignment.assignee.id, + } + for assignment in instance.assignments.all() + ] + class Meta: model = Example fields = [ @@ -45,8 +63,10 @@ class Meta: "text", "is_confirmed", "upload_name", + "score", + "assignments", ] - read_only_fields = ["filename", "is_confirmed", "upload_name"] + read_only_fields = ["filename", "is_confirmed", "upload_name", "assignments"] class ExampleStateSerializer(serializers.ModelSerializer): diff --git a/backend/examples/tests/test_assignment.py b/backend/examples/tests/test_assignment.py new file mode 100644 index 0000000000..2aa9e2571a --- /dev/null +++ b/backend/examples/tests/test_assignment.py @@ -0,0 +1,117 @@ +from rest_framework import status +from rest_framework.reverse import reverse + +from .utils import make_assignment, make_doc +from api.tests.utils import CRUDMixin +from examples.models import Assignment +from projects.models import Member +from projects.tests.utils import prepare_project +from users.tests.utils import make_user + + +class TestAssignmentList(CRUDMixin): + def setUp(self): + self.project = prepare_project() + self.non_member = make_user() + self.example = make_doc(self.project.item) + make_assignment(self.project.item, self.example, self.project.admin) + self.data = {"example": self.example.id, "assignee": self.project.staffs[0].id} + self.url = reverse(viewname="assignment_list", args=[self.project.item.id]) + + def test_allow_project_member_to_list_assignments(self): + for member in self.project.members: + self.assert_fetch(member, status.HTTP_200_OK) + + def test_denies_non_project_member_to_list_assignments(self): + self.assert_fetch(self.non_member, status.HTTP_403_FORBIDDEN) + + def test_denies_unauthenticated_user_to_list_assignments(self): + self.assert_fetch(expected=status.HTTP_403_FORBIDDEN) + + def test_allows_project_admin_to_assign(self): + response = self.assert_create(self.project.admin, status.HTTP_201_CREATED) + self.assertEqual(response.data["example"], self.data["example"]) + self.assertEqual(response.data["assignee"], self.data["assignee"]) + + def test_denies_non_admin_to_assign(self): + for member in self.project.staffs: + self.assert_create(member, status.HTTP_403_FORBIDDEN) + + def test_denies_non_project_member_to_assign(self): + self.assert_create(self.non_member, status.HTTP_403_FORBIDDEN) + + def test_denies_unauthenticated_user_to_assign(self): + self.assert_create(expected=status.HTTP_403_FORBIDDEN) + + +class TestAssignmentDetail(CRUDMixin): + def setUp(self): + self.project = prepare_project() + self.non_member = make_user() + example = make_doc(self.project.item) + assignment = make_assignment(self.project.item, example, self.project.admin) + self.data = {"assignee": self.project.staffs[0].id} + self.url = reverse(viewname="assignment_detail", args=[self.project.item.id, assignment.id]) + + def test_allows_project_member_to_get_assignment(self): + for member in self.project.members: + self.assert_fetch(member, status.HTTP_200_OK) + + def test_denies_non_project_member_to_get_assignment(self): + self.assert_fetch(self.non_member, status.HTTP_403_FORBIDDEN) + + def test_denies_unauthenticated_user_to_get_assignment(self): + self.assert_fetch(expected=status.HTTP_403_FORBIDDEN) + + def test_allows_project_admin_to_reassign(self): + response = self.assert_update(self.project.admin, status.HTTP_200_OK) + self.assertEqual(response.data["assignee"], self.data["assignee"]) + + def test_denies_non_admin_to_reassign(self): + for member in self.project.staffs: + self.assert_update(member, status.HTTP_403_FORBIDDEN) + + def test_denies_non_project_member_to_reassign(self): + self.assert_update(self.non_member, status.HTTP_403_FORBIDDEN) + + def test_denies_unauthenticated_user_to_reassign(self): + self.assert_update(expected=status.HTTP_403_FORBIDDEN) + + def test_allows_project_admin_to_unassign(self): + self.assert_delete(self.project.admin, status.HTTP_204_NO_CONTENT) + + def test_denies_non_admin_to_unassign(self): + for member in self.project.staffs: + self.assert_delete(member, status.HTTP_403_FORBIDDEN) + + def test_denies_non_project_member_to_unassign(self): + self.assert_delete(self.non_member, status.HTTP_403_FORBIDDEN) + + def test_denies_unauthenticated_user_to_unassign(self): + self.assert_delete(expected=status.HTTP_403_FORBIDDEN) + + +class TestAssignmentBulk(CRUDMixin): + def setUp(self): + self.project = prepare_project() + self.non_member = make_user() + self.example = make_doc(self.project.item) + members = Member.objects.filter(project=self.project.item) + workloads = [{"member_id": member.id, "weight": 100} for member in members] + self.data = {"strategy_name": "sampling_without_replacement", "workloads": workloads} + self.url = reverse(viewname="bulk_assignment", args=[self.project.item.id]) + + def test_denies_non_admin_to_bulk_assign(self): + for member in self.project.staffs: + self.assert_create(member, status.HTTP_403_FORBIDDEN) + + def test_denies_non_project_member_to_bulk_assign(self): + self.assert_create(self.non_member, status.HTTP_403_FORBIDDEN) + + def test_denies_unauthenticated_user_to_bulk_assign(self): + self.assert_create(expected=status.HTTP_403_FORBIDDEN) + + def test_allows_project_admin_to_bulk_assign(self): + self.assert_create(self.project.admin, status.HTTP_201_CREATED) + expected = self.project.item.examples.count() * len(self.project.members) + self.assertEqual(Assignment.objects.count(), expected) diff --git a/backend/examples/tests/test_document.py b/backend/examples/tests/test_example.py similarity index 54% rename from backend/examples/tests/test_document.py rename to backend/examples/tests/test_example.py index ccb67f49fa..b39eed4e7f 100644 --- a/backend/examples/tests/test_document.py +++ b/backend/examples/tests/test_example.py @@ -1,24 +1,25 @@ -from django.conf import settings from django.utils.http import urlencode from rest_framework import status from rest_framework.reverse import reverse -from .utils import make_doc, make_example_state +from .utils import make_assignment, make_doc, make_example_state from api.tests.utils import CRUDMixin -from projects.models import DOCUMENT_CLASSIFICATION -from projects.tests.utils import assign_user_to_role, prepare_project +from projects.models import ProjectType +from projects.tests.utils import prepare_project from users.tests.utils import make_user class TestExampleListAPI(CRUDMixin): def setUp(self): - self.project = prepare_project(task=DOCUMENT_CLASSIFICATION) + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION) self.non_member = make_user() self.example = make_doc(self.project.item) + for member in self.project.members: + make_assignment(self.project.item, self.example, member) self.data = {"text": "example"} self.url = reverse(viewname="example_list", args=[self.project.item.id]) - def test_allows_project_member_to_list_docs(self): + def test_allows_project_member_to_list_examples(self): for member in self.project.members: response = self.assert_fetch(member, status.HTTP_200_OK) self.assertEqual(response.data["count"], 1) @@ -26,33 +27,24 @@ def test_allows_project_member_to_list_docs(self): for item in response.data["results"]: self.assertIn("text", item) - def test_denies_non_project_member_to_list_docs(self): + def test_denies_non_project_member_to_list_examples(self): self.assert_fetch(self.non_member, status.HTTP_403_FORBIDDEN) - def test_denies_unauthenticated_user_to_list_docs(self): + def test_denies_unauthenticated_user_to_list_examples(self): self.assert_fetch(expected=status.HTTP_403_FORBIDDEN) - def test_allows_project_admin_to_create_doc(self): + def test_allows_project_admin_to_create_example(self): response = self.assert_create(self.project.admin, status.HTTP_201_CREATED) self.assertEqual(response.data["text"], self.data["text"]) - def test_denies_project_staff_to_create_doc(self): + def test_denies_non_admin_to_create_example(self): for member in self.project.staffs: self.assert_create(member, status.HTTP_403_FORBIDDEN) - def test_denies_unauthenticated_user_to_create_doc(self): + def test_denies_unauthenticated_user_to_create_example(self): self.assert_create(expected=status.HTTP_403_FORBIDDEN) - def test_is_confirmed(self): - make_example_state(self.example, self.project.admin) - response = self.assert_fetch(self.project.admin, status.HTTP_200_OK) - self.assertTrue(response.data["results"][0]["is_confirmed"]) - - def test_is_not_confirmed(self): - response = self.assert_fetch(self.project.admin, status.HTTP_200_OK) - self.assertFalse(response.data["results"][0]["is_confirmed"]) - - def test_does_not_share_another_user_confirmed(self): + def test_example_is_not_approved_if_another_user_approve_it(self): make_example_state(self.example, self.project.admin) response = self.assert_fetch(self.project.annotator, status.HTTP_200_OK) self.assertFalse(response.data["results"][0]["is_confirmed"]) @@ -60,23 +52,13 @@ def test_does_not_share_another_user_confirmed(self): class TestExampleListCollaborative(CRUDMixin): def setUp(self): - self.project = prepare_project(task=DOCUMENT_CLASSIFICATION) + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION, collaborative_annotation=True) self.example = make_doc(self.project.item) + for member in self.project.members: + make_assignment(self.project.item, self.example, member) self.url = reverse(viewname="example_list", args=[self.project.item.id]) - def test_shares_confirmed_in_same_role(self): - annotator1 = make_user() - assign_user_to_role(annotator1, self.project.item, settings.ROLE_ANNOTATOR) - annotator2 = make_user() - assign_user_to_role(annotator2, self.project.item, settings.ROLE_ANNOTATOR) - - make_example_state(self.example, annotator1) - response = self.assert_fetch(annotator1, status.HTTP_200_OK) - self.assertTrue(response.data["results"][0]["is_confirmed"]) - response = self.assert_fetch(annotator2, status.HTTP_200_OK) - self.assertTrue(response.data["results"][0]["is_confirmed"]) - - def test_does_not_share_confirmed_in_other_role(self): + def test_example_is_approved_if_someone_approve_it(self): admin = self.project.admin approver = self.project.approver @@ -84,14 +66,20 @@ def test_does_not_share_confirmed_in_other_role(self): response = self.assert_fetch(admin, status.HTTP_200_OK) self.assertTrue(response.data["results"][0]["is_confirmed"]) response = self.assert_fetch(approver, status.HTTP_200_OK) - self.assertFalse(response.data["results"][0]["is_confirmed"]) + self.assertTrue(response.data["results"][0]["is_confirmed"]) class TestExampleListFilter(CRUDMixin): def setUp(self): - self.project = prepare_project(task=DOCUMENT_CLASSIFICATION) - self.example = make_doc(self.project.item) - make_example_state(self.example, self.project.admin) + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION) + example1 = make_doc(self.project.item) + example2 = make_doc(self.project.item) + example3 = make_doc(self.project.item) + for member in self.project.members: + make_assignment(self.project.item, example1, member) + make_assignment(self.project.item, example2, member) + make_assignment(self.project.item, example3, member) + make_example_state(example1, self.project.admin) def reverse(self, query_kwargs=None): base_url = reverse(viewname="example_list", args=[self.project.item.id]) @@ -102,67 +90,59 @@ def assert_filter(self, data, user, expected): response = self.assert_fetch(user, status.HTTP_200_OK) self.assertEqual(response.data["count"], expected) - def test_returns_example_if_confirmed_is_true(self): + def test_returns_only_approved_examples(self): user = self.project.admin self.assert_filter(data={"confirmed": "True"}, user=user, expected=1) - def test_does_not_return_example_if_confirmed_is_false(self): + def test_returns_only_non_approved_examples(self): user = self.project.admin - self.assert_filter(data={"confirmed": "False"}, user=user, expected=0) + self.assert_filter(data={"confirmed": "False"}, user=user, expected=2) - def test_returns_example_if_confirmed_is_empty(self): + def test_returns_all_examples(self): user = self.project.admin - self.assert_filter(data={"confirmed": ""}, user=user, expected=1) + self.assert_filter(data={"confirmed": ""}, user=user, expected=3) - def test_does_not_return_example_if_user_is_different(self): + def test_does_not_return_approved_example_to_another_user(self): user = self.project.approver self.assert_filter(data={"confirmed": "True"}, user=user, expected=0) - def test_returns_example_if_user_is_different(self): - user = self.project.approver - self.assert_filter(data={"confirmed": "False"}, user=user, expected=1) - - def test_returns_example_if_user_is_different_and_confirmed_is_empty(self): - user = self.project.approver - self.assert_filter(data={"confirmed": ""}, user=user, expected=1) - class TestExampleDetail(CRUDMixin): def setUp(self): - self.project = prepare_project(task=DOCUMENT_CLASSIFICATION) + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION) self.non_member = make_user() - doc = make_doc(self.project.item) + example = make_doc(self.project.item) self.data = {"text": "example"} - self.url = reverse(viewname="example_detail", args=[self.project.item.id, doc.id]) + self.url = reverse(viewname="example_detail", args=[self.project.item.id, example.id]) - def test_allows_project_member_to_get_doc(self): + def test_allows_project_member_to_get_example(self): for member in self.project.members: response = self.assert_fetch(member, status.HTTP_200_OK) self.assertIn("text", response.data) - def test_denies_non_project_member_to_get_doc(self): + def test_denies_non_project_member_to_get_example(self): self.assert_fetch(self.non_member, status.HTTP_403_FORBIDDEN) - def test_denies_unauthenticated_user_to_get_doc(self): + def test_denies_unauthenticated_user_to_get_example(self): self.assert_fetch(expected=status.HTTP_403_FORBIDDEN) - def test_allows_project_admin_to_update_doc(self): + def test_allows_project_admin_to_update_example(self): response = self.assert_update(self.project.admin, status.HTTP_200_OK) self.assertEqual(response.data["text"], self.data["text"]) - def test_denies_project_staff_to_update_doc(self): + def test_denies_non_admin_to_update_example(self): for member in self.project.staffs: self.assert_update(member, status.HTTP_403_FORBIDDEN) - def test_denies_non_project_member_to_update_doc(self): + def test_denies_non_project_member_to_update_example(self): self.assert_update(self.non_member, status.HTTP_403_FORBIDDEN) - def test_allows_project_admin_to_delete_doc(self): + def test_allows_project_admin_to_delete_example(self): self.assert_delete(self.project.admin, status.HTTP_204_NO_CONTENT) - def test_denies_project_staff_to_delete_doc(self): + def test_denies_non_admin_to_delete_example(self): for member in self.project.staffs: self.assert_delete(member, status.HTTP_403_FORBIDDEN) - def test_denies_non_project_member_to_delete_doc(self): + def test_denies_non_project_member_to_delete_example(self): self.assert_delete(self.non_member, status.HTTP_403_FORBIDDEN) diff --git a/backend/examples/tests/test_filters.py b/backend/examples/tests/test_filters.py index 2d0a6df0ff..a6ae2e97f8 100644 --- a/backend/examples/tests/test_filters.py +++ b/backend/examples/tests/test_filters.py @@ -1,10 +1,12 @@ from unittest.mock import MagicMock from django.test import TestCase +from model_mommy import mommy from .utils import make_doc, make_example_state from examples.filters import ExampleFilter from examples.models import Example +from projects.models import ProjectType from projects.tests.utils import prepare_project @@ -48,6 +50,17 @@ def test_returns_example_if_user_is_different_and_confirmed_is_empty(self): self.assert_filter(data={"confirmed": ""}, expected=1) +class TestLabelFilter(TestFilterMixin): + def setUp(self): + self.project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION) + self.prepare(project=self.project) + self.label_type = mommy.make("CategoryType", project=self.project.item, text="positive") + mommy.make("Category", example=self.example, label=self.label_type) + + def test_returns_example_with_positive_label(self): + self.assert_filter(data={"label": self.label_type.text}, expected=1) + + class TestExampleFilterOnCollaborative(TestFilterMixin): def setUp(self): self.project = prepare_project(task="DocumentClassification", collaborative_annotation=True) diff --git a/backend/examples/tests/test_models.py b/backend/examples/tests/test_models.py index 96844ed057..0b406a6a5a 100644 --- a/backend/examples/tests/test_models.py +++ b/backend/examples/tests/test_models.py @@ -2,13 +2,13 @@ from model_mommy import mommy from examples.models import ExampleState -from projects.models import IMAGE_CLASSIFICATION, SEQUENCE_LABELING +from projects.models import ProjectType from projects.tests.utils import prepare_project class TestExampleState(TestCase): def setUp(self): - self.project = prepare_project(SEQUENCE_LABELING) + self.project = prepare_project(ProjectType.SEQUENCE_LABELING) self.example = mommy.make("Example", project=self.project.item) self.other = mommy.make("Example", project=self.project.item) self.examples = self.project.item.examples.all() @@ -55,16 +55,17 @@ def test_user_count_after_multiple_user_confirmation(self): expected_progress = [{"user": member.username, "done": 0} for member in self.project.members] expected_progress[0]["done"] = 1 expected_progress[1]["done"] = 1 - self.assertEqual(progress, {"total": 2, "progress": expected_progress}) + self.assertEqual(progress["total"], 2) + self.assertCountEqual(progress["progress"], expected_progress) class TestExample(TestCase): def test_text_project_returns_text_as_data_property(self): - project = prepare_project(SEQUENCE_LABELING) + project = prepare_project(ProjectType.SEQUENCE_LABELING) example = mommy.make("Example", project=project.item) self.assertEqual(example.text, example.data) def test_image_project_returns_filename_as_data_property(self): - project = prepare_project(IMAGE_CLASSIFICATION) + project = prepare_project(ProjectType.IMAGE_CLASSIFICATION) example = mommy.make("Example", project=project.item) self.assertEqual(str(example.filename), example.data) diff --git a/backend/examples/tests/test_usecase.py b/backend/examples/tests/test_usecase.py new file mode 100644 index 0000000000..3bd3e3b61b --- /dev/null +++ b/backend/examples/tests/test_usecase.py @@ -0,0 +1,33 @@ +from django.test import TestCase +from model_mommy import mommy + +from examples.assignment.usecase import StrategyName, bulk_assign +from projects.models import Member, ProjectType +from projects.tests.utils import prepare_project + + +class TestBulkAssignment(TestCase): + def setUp(self): + self.project = prepare_project(ProjectType.SEQUENCE_LABELING) + self.member_ids = list(Member.objects.values_list("id", flat=True)) + self.example = mommy.make("Example", project=self.project.item) + + def test_raise_error_if_weights_is_invalid(self): + with self.assertRaises(ValueError): + bulk_assign( + self.project.item.id, StrategyName.weighted_sequential, self.member_ids, [0] * len(self.member_ids) + ) + + def test_raise_error_if_passing_wrong_member_ids(self): + with self.assertRaises(ValueError): + bulk_assign( + self.project.item.id, + StrategyName.weighted_sequential, + self.member_ids + [100], + [0] * len(self.member_ids), + ) + + def test_assign_examples(self): + bulk_assign(self.project.item.id, StrategyName.weighted_sequential, self.member_ids, [100, 0, 0]) + self.assertEqual(self.example.assignments.count(), 1) + self.assertEqual(self.example.assignments.first().assignee, self.project.admin) diff --git a/backend/examples/tests/utils.py b/backend/examples/tests/utils.py index 06a97bdd09..9a5ab3c8fc 100644 --- a/backend/examples/tests/utils.py +++ b/backend/examples/tests/utils.py @@ -15,3 +15,7 @@ def make_image(project, filepath): def make_example_state(example, user): return mommy.make("ExampleState", example=example, confirmed_by=user) + + +def make_assignment(project, example, user): + return mommy.make("Assignment", project=project, example=example, assignee=user) diff --git a/backend/examples/urls.py b/backend/examples/urls.py index 89d505614f..56c6cbdb2f 100644 --- a/backend/examples/urls.py +++ b/backend/examples/urls.py @@ -1,10 +1,20 @@ from django.urls import path +from .views.assignment import ( + AssignmentDetail, + AssignmentList, + BulkAssignment, + ResetAssignment, +) from .views.comment import CommentDetail, CommentList from .views.example import ExampleDetail, ExampleList from .views.example_state import ExampleStateList urlpatterns = [ + path(route="assignments", view=AssignmentList.as_view(), name="assignment_list"), + path(route="assignments/", view=AssignmentDetail.as_view(), name="assignment_detail"), + path(route="assignments/reset", view=ResetAssignment.as_view(), name="assignment_reset"), + path(route="assignments/bulk_assign", view=BulkAssignment.as_view(), name="bulk_assignment"), path(route="examples", view=ExampleList.as_view(), name="example_list"), path(route="examples/", view=ExampleDetail.as_view(), name="example_detail"), path(route="comments", view=CommentList.as_view(), name="comment_list"), diff --git a/backend/examples/views/assignment.py b/backend/examples/views/assignment.py new file mode 100644 index 0000000000..08c1087342 --- /dev/null +++ b/backend/examples/views/assignment.py @@ -0,0 +1,88 @@ +from django.shortcuts import get_object_or_404 +from django_filters.rest_framework import DjangoFilterBackend +from pydantic import ValidationError +from rest_framework import filters, generics, status +from rest_framework.permissions import IsAuthenticated +from rest_framework.views import APIView, Response + +from examples.assignment.strategies import StrategyName +from examples.assignment.usecase import bulk_assign +from examples.assignment.workload import WorkloadAllocation +from examples.models import Assignment +from examples.serializers import AssignmentSerializer +from projects.models import Project +from projects.permissions import IsProjectAdmin, IsProjectStaffAndReadOnly + + +class AssignmentList(generics.ListCreateAPIView): + serializer_class = AssignmentSerializer + permission_classes = [IsAuthenticated & (IsProjectAdmin | IsProjectStaffAndReadOnly)] + filter_backends = (DjangoFilterBackend, filters.OrderingFilter) + ordering_fields = ("created_at", "updated_at") + model = Assignment + + @property + def project(self): + return get_object_or_404(Project, pk=self.kwargs["project_id"]) + + def get_queryset(self): + queryset = self.model.objects.filter(project=self.project, assignee=self.request.user) + return queryset + + def perform_create(self, serializer): + serializer.save(project=self.project) + + +class AssignmentDetail(generics.RetrieveUpdateDestroyAPIView): + queryset = Assignment.objects.all() + serializer_class = AssignmentSerializer + lookup_url_kwarg = "assignment_id" + permission_classes = [IsAuthenticated & (IsProjectAdmin | IsProjectStaffAndReadOnly)] + + +class ResetAssignment(APIView): + permission_classes = [IsAuthenticated & IsProjectAdmin] + + @property + def project(self): + return get_object_or_404(Project, pk=self.kwargs["project_id"]) + + def delete(self, *args, **kwargs): + Assignment.objects.filter(project=self.project).delete() + return Response(status=status.HTTP_204_NO_CONTENT) + + +class BulkAssignment(APIView): + serializer_class = AssignmentSerializer + permission_classes = [IsAuthenticated & IsProjectAdmin] + + def post(self, *args, **kwargs): + try: + strategy_name = StrategyName[self.request.data["strategy_name"]] + except KeyError: + return Response( + {"detail": "Invalid strategy name"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + try: + workload_allocation = WorkloadAllocation(workloads=self.request.data["workloads"]) + except ValidationError as e: + return Response( + {"detail": e.errors()}, + status=status.HTTP_400_BAD_REQUEST, + ) + + try: + bulk_assign( + project_id=self.kwargs["project_id"], + strategy_name=strategy_name, + member_ids=workload_allocation.member_ids, + weights=workload_allocation.weights, + ) + except ValueError as e: + return Response( + {"detail": str(e)}, + status=status.HTTP_400_BAD_REQUEST, + ) + return Response(status=status.HTTP_201_CREATED) diff --git a/backend/examples/views/comment.py b/backend/examples/views/comment.py index 928f3890f1..dadb8c72f1 100644 --- a/backend/examples/views/comment.py +++ b/backend/examples/views/comment.py @@ -12,9 +12,10 @@ class CommentList(generics.ListCreateAPIView): permission_classes = [IsAuthenticated & IsProjectMember] serializer_class = CommentSerializer - filter_backends = (DjangoFilterBackend, filters.SearchFilter) + filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter) filterset_fields = ["example"] search_fields = ("text",) + ordering_fields = ("created_at", "example") def get_queryset(self): queryset = Comment.objects.filter(example__project_id=self.kwargs["project_id"]) diff --git a/backend/examples/views/example.py b/backend/examples/views/example.py index 2e2af005da..f5fe041a26 100644 --- a/backend/examples/views/example.py +++ b/backend/examples/views/example.py @@ -1,6 +1,3 @@ -import random - -from django.db.models import F from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend from rest_framework import filters, generics, status @@ -10,7 +7,7 @@ from examples.filters import ExampleFilter from examples.models import Example from examples.serializers import ExampleSerializer -from projects.models import Project +from projects.models import Member, Project from projects.permissions import IsProjectAdmin, IsProjectStaffAndReadOnly @@ -18,24 +15,23 @@ class ExampleList(generics.ListCreateAPIView): serializer_class = ExampleSerializer permission_classes = [IsAuthenticated & (IsProjectAdmin | IsProjectStaffAndReadOnly)] filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter) - ordering_fields = ("created_at", "updated_at") + ordering_fields = ("created_at", "updated_at", "score") search_fields = ("text", "filename") model = Example - filter_class = ExampleFilter + filterset_class = ExampleFilter @property def project(self): return get_object_or_404(Project, pk=self.kwargs["project_id"]) def get_queryset(self): - queryset = self.model.objects.filter(project=self.project) + member = get_object_or_404(Member, project=self.project, user=self.request.user) + if member.is_admin(): + return self.model.objects.filter(project=self.project) + + queryset = self.model.objects.filter(project=self.project, assignments__assignee=self.request.user) if self.project.random_order: - # Todo: fix the algorithm. - random.seed(self.request.user.id) - value = random.randrange(2, 20) - queryset = queryset.annotate(sort_id=F("id") % value).order_by("sort_id", "id") - else: - queryset = queryset.order_by("created_at") + queryset = queryset.order_by("assignments__id") return queryset def perform_create(self, serializer): diff --git a/backend/label_types/tests/test_views.py b/backend/label_types/tests/test_views.py index 0b46d12a6e..45a2c22c5b 100644 --- a/backend/label_types/tests/test_views.py +++ b/backend/label_types/tests/test_views.py @@ -7,7 +7,7 @@ from .utils import make_label from api.tests.utils import CRUDMixin -from projects.models import DOCUMENT_CLASSIFICATION +from projects.models import ProjectType from projects.tests.utils import make_project, prepare_project from users.tests.utils import make_user @@ -15,16 +15,18 @@ class TestLabelList(CRUDMixin): - @classmethod - def setUpTestData(cls): - cls.non_member = make_user() - cls.project_a = prepare_project(DOCUMENT_CLASSIFICATION) - cls.label = make_label(cls.project_a.item) - cls.url = reverse(viewname="category_types", args=[cls.project_a.item.id]) + def setUp(self): + self.non_member = make_user() + self.project_a = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION) + self.label = make_label(self.project_a.item) + self.url = reverse(viewname="category_types", args=[self.project_a.item.id]) # Ensure that the API does not return the labels of the other project. - cls.project_b = make_project(task="Any", users=["admin"], roles=[settings.ROLE_PROJECT_ADMIN]) - make_label(cls.project_b.item) + self.project_b = make_project(task="Any", users=["admin"], roles=[settings.ROLE_PROJECT_ADMIN]) + make_label(self.project_b.item) + + # for label creation + self.data = {"text": "example"} def test_returns_labels_to_project_member(self): for member in self.project_a.members: @@ -38,32 +40,11 @@ def test_does_not_return_labels_to_non_project_member(self): def test_does_not_return_labels_to_unauthenticated_user(self): self.assert_fetch(expected=status.HTTP_403_FORBIDDEN) - -class TestLabelSearch(CRUDMixin): - def setUp(self): - self.project = prepare_project(DOCUMENT_CLASSIFICATION) - make_label(self.project.item) - self.url = reverse(viewname="category_types", args=[self.project.item.id]) - - def test_search(self): - for member in self.project.members: - response = self.assert_fetch(member, status.HTTP_200_OK) - self.assertEqual(len(response.data), 1) - - -class TestLabelCreate(CRUDMixin): - @classmethod - def setUpTestData(cls): - cls.non_member = make_user(DOCUMENT_CLASSIFICATION) - cls.project = prepare_project() - cls.url = reverse(viewname="category_types", args=[cls.project.item.id]) - cls.data = {"text": "example"} - def test_allows_admin_to_create_label(self): - self.assert_create(self.project.admin, status.HTTP_201_CREATED) + self.assert_create(self.project_a.admin, status.HTTP_201_CREATED) def test_denies_project_staff_to_create_label(self): - for member in self.project.staffs: + for member in self.project_a.staffs: self.assert_create(member, status.HTTP_403_FORBIDDEN) def test_denies_non_project_member_to_create_label(self): @@ -72,12 +53,37 @@ def test_denies_non_project_member_to_create_label(self): def test_denies_unauthenticated_user_to_create_label(self): self.assert_create(expected=status.HTTP_403_FORBIDDEN) + def test_allows_admin_to_bulk_delete_label(self): + self.assert_delete(self.project_a.admin, status.HTTP_204_NO_CONTENT, data={"ids": [self.label.id]}) + + def test_denies_project_staff_to_bulk_delete_label(self): + member = self.project_a.staffs[0] + self.assert_delete(member, status.HTTP_403_FORBIDDEN, data={"ids": [self.label.id]}) + + +class TestAllowMemberToCreateLabelType(CRUDMixin): + @classmethod + def setUpTestData(cls): + cls.project = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION, allow_member_to_create_label_type=True) + cls.label = make_label(cls.project.item) + cls.url = reverse(viewname="category_types", args=[cls.project.item.id]) + cls.data = {"text": "example"} + + def test_allows_member_to_create_label_type(self): + for member in self.project.members: + self.data["text"] = member.username + self.assert_create(member, status.HTTP_201_CREATED) + + def test_denies_project_staff_to_bulk_delete_label(self): + member = self.project.staffs[0] + self.assert_delete(member, status.HTTP_403_FORBIDDEN, data={"ids": [self.label.id]}) + class TestLabelDetailAPI(CRUDMixin): @classmethod def setUpTestData(cls): cls.non_member = make_user() - cls.project = prepare_project(DOCUMENT_CLASSIFICATION) + cls.project = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION) cls.label = make_label(cls.project.item) cls.url = reverse(viewname="category_type", args=[cls.project.item.id, cls.label.id]) cls.data = {"text": "example"} @@ -125,7 +131,7 @@ class TestLabelUploadAPI(APITestCase): @classmethod def setUpTestData(cls): cls.non_member = make_user() - cls.project = prepare_project(DOCUMENT_CLASSIFICATION) + cls.project = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION) cls.url = reverse(viewname="category_type_upload", args=[cls.project.item.id]) def assert_upload_file(self, filename, user=None, expected_status=status.HTTP_403_FORBIDDEN): diff --git a/backend/label_types/tests/utils.py b/backend/label_types/tests/utils.py index 8562aadf14..19985b210a 100644 --- a/backend/label_types/tests/utils.py +++ b/backend/label_types/tests/utils.py @@ -1,10 +1,13 @@ from model_mommy import mommy -from projects.models import BOUNDING_BOX +from projects.models import ProjectType def make_label(project, **kwargs): - if project.project_type.endswith("Classification") or project.project_type == BOUNDING_BOX: + if project.project_type.endswith("Classification") or project.project_type in { + ProjectType.BOUNDING_BOX, + ProjectType.SEGMENTATION, + }: return mommy.make("CategoryType", project=project, **kwargs) else: return mommy.make("SpanType", project=project, **kwargs) diff --git a/backend/label_types/views.py b/backend/label_types/views.py index 875cbc8905..a783d78840 100644 --- a/backend/label_types/views.py +++ b/backend/label_types/views.py @@ -2,6 +2,7 @@ import re from django.db import IntegrityError, transaction +from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend from rest_framework import generics, status from rest_framework.exceptions import ParseError @@ -18,7 +19,12 @@ RelationTypeSerializer, SpanTypeSerializer, ) -from projects.permissions import IsProjectAdmin, IsProjectStaffAndReadOnly +from projects.models import Project +from projects.permissions import ( + IsProjectAdmin, + IsProjectMember, + IsProjectStaffAndReadOnly, +) def camel_to_snake(name): @@ -35,7 +41,14 @@ class LabelList(generics.ListCreateAPIView): filter_backends = [DjangoFilterBackend] serializer_class = LabelSerializer pagination_class = None - permission_classes = [IsAuthenticated & (IsProjectAdmin | IsProjectStaffAndReadOnly)] + + def get_permissions(self): + project = get_object_or_404(Project, pk=self.kwargs["project_id"]) + if project.allow_member_to_create_label_type and self.request.method == "POST": + self.permission_classes = [IsAuthenticated & IsProjectMember] + else: + self.permission_classes = [IsAuthenticated & (IsProjectAdmin | IsProjectStaffAndReadOnly)] + return super().get_permissions() def get_queryset(self): return self.model.objects.filter(project=self.kwargs["project_id"]) diff --git a/backend/labels/managers.py b/backend/labels/managers.py index 6d7540c7ae..ac48566d9b 100644 --- a/backend/labels/managers.py +++ b/backend/labels/managers.py @@ -29,7 +29,9 @@ def calc_label_distribution(self, examples, members, labels): username = item["user__username"] label = item[f"{self.label_type_field}__text"] count = item["count"] - distribution[username][label] = count + # Skip users who are no longer members of the project + if username in distribution: + distribution[username][label] = count return distribution def get_labels(self, label, project): diff --git a/backend/labels/tests/test_category.py b/backend/labels/tests/test_category.py index 4cdb6b2772..3bcfbdfd0d 100644 --- a/backend/labels/tests/test_category.py +++ b/backend/labels/tests/test_category.py @@ -5,7 +5,7 @@ from model_mommy import mommy from labels.models import Category -from projects.models import DOCUMENT_CLASSIFICATION +from projects.models import ProjectType from projects.tests.utils import prepare_project @@ -16,7 +16,7 @@ class TestCategoryLabeling(abc.ABC, TestCase): @classmethod def setUpTestData(cls): cls.project = prepare_project( - DOCUMENT_CLASSIFICATION, + ProjectType.DOCUMENT_CLASSIFICATION, single_class_classification=cls.exclusive, collaborative_annotation=cls.collaborative, ) diff --git a/backend/labels/tests/test_relation.py b/backend/labels/tests/test_relation.py index 738a2b7ebd..1612b913d7 100644 --- a/backend/labels/tests/test_relation.py +++ b/backend/labels/tests/test_relation.py @@ -2,14 +2,14 @@ from django.test import TestCase from model_mommy import mommy -from projects.models import SEQUENCE_LABELING +from projects.models import ProjectType from projects.tests.utils import prepare_project class TestRelationLabeling(TestCase): @classmethod def setUpTestData(cls): - cls.project = prepare_project(SEQUENCE_LABELING) + cls.project = prepare_project(ProjectType.SEQUENCE_LABELING) cls.example = mommy.make("Example", project=cls.project.item) cls.label_type = mommy.make("RelationType", project=cls.project.item) cls.user = cls.project.admin diff --git a/backend/labels/tests/test_span.py b/backend/labels/tests/test_span.py index 8a758a24b5..1213ac8e7f 100644 --- a/backend/labels/tests/test_span.py +++ b/backend/labels/tests/test_span.py @@ -1,13 +1,12 @@ import abc from django.core.exceptions import ValidationError -from django.db import IntegrityError from django.test import TestCase from model_mommy import mommy from label_types.models import SpanType from labels.models import Span -from projects.models import SEQUENCE_LABELING +from projects.models import ProjectType from projects.tests.utils import prepare_project @@ -18,7 +17,7 @@ class TestSpanLabeling(abc.ABC, TestCase): @classmethod def setUpTestData(cls): cls.project = prepare_project( - SEQUENCE_LABELING, allow_overlapping=cls.overlapping, collaborative_annotation=cls.collaborative + ProjectType.SEQUENCE_LABELING, allow_overlapping=cls.overlapping, collaborative_annotation=cls.collaborative ) cls.example = mommy.make("Example", project=cls.project.item) cls.label_type = mommy.make("SpanType", project=cls.project.item) @@ -137,20 +136,20 @@ def test_allow_another_user_to_annotate_same_span(self): class TestSpan(TestCase): def setUp(self): - self.project = prepare_project(SEQUENCE_LABELING, allow_overlapping=False) + self.project = prepare_project(ProjectType.SEQUENCE_LABELING, allow_overlapping=False) self.example = mommy.make("Example", project=self.project.item) self.user = self.project.admin def test_start_offset_is_not_negative(self): - with self.assertRaises(IntegrityError): + with self.assertRaises(ValidationError): mommy.make("Span", start_offset=-1, end_offset=0) def test_end_offset_is_not_negative(self): - with self.assertRaises(IntegrityError): + with self.assertRaises(ValidationError): mommy.make("Span", start_offset=-2, end_offset=-1) def test_start_offset_is_less_than_end_offset(self): - with self.assertRaises(IntegrityError): + with self.assertRaises(ValidationError): mommy.make("Span", start_offset=0, end_offset=0) def test_unique_constraint(self): @@ -168,7 +167,7 @@ def test_unique_constraint_violated(self): ) def test_unique_constraint_if_overlapping_is_allowed(self): - project = prepare_project(SEQUENCE_LABELING, allow_overlapping=True) + project = prepare_project(ProjectType.SEQUENCE_LABELING, allow_overlapping=True) example = mommy.make("Example", project=project.item) user = project.admin mommy.make("Span", example=example, start_offset=5, end_offset=10, user=user) @@ -184,7 +183,7 @@ def test_update(self): class TestSpanWithoutCollaborativeMode(TestCase): def setUp(self): - self.project = prepare_project(SEQUENCE_LABELING, False, allow_overlapping=False) + self.project = prepare_project(ProjectType.SEQUENCE_LABELING, False, allow_overlapping=False) self.example = mommy.make("Example", project=self.project.item) def test_allow_users_to_create_same_spans(self): @@ -194,14 +193,14 @@ def test_allow_users_to_create_same_spans(self): class TestSpanWithCollaborativeMode(TestCase): def test_deny_users_to_create_same_spans(self): - project = prepare_project(SEQUENCE_LABELING, True, allow_overlapping=False) + project = prepare_project(ProjectType.SEQUENCE_LABELING, True, allow_overlapping=False) example = mommy.make("Example", project=project.item) mommy.make("Span", example=example, start_offset=5, end_offset=10, user=project.admin) with self.assertRaises(ValidationError): mommy.make("Span", example=example, start_offset=5, end_offset=10, user=project.approver) def test_allow_users_to_create_same_spans_if_overlapping_is_allowed(self): - project = prepare_project(SEQUENCE_LABELING, True, allow_overlapping=True) + project = prepare_project(ProjectType.SEQUENCE_LABELING, True, allow_overlapping=True) example = mommy.make("Example", project=project.item) mommy.make("Span", example=example, start_offset=5, end_offset=10, user=project.admin) mommy.make("Span", example=example, start_offset=5, end_offset=10, user=project.approver) @@ -209,7 +208,7 @@ def test_allow_users_to_create_same_spans_if_overlapping_is_allowed(self): class TestLabelDistribution(TestCase): def setUp(self): - self.project = prepare_project(SEQUENCE_LABELING, allow_overlapping=False) + self.project = prepare_project(ProjectType.SEQUENCE_LABELING, allow_overlapping=False) self.example = mommy.make("Example", project=self.project.item) self.user = self.project.admin diff --git a/backend/labels/tests/test_text_label.py b/backend/labels/tests/test_text_label.py index 096e544072..71cbddd6b1 100644 --- a/backend/labels/tests/test_text_label.py +++ b/backend/labels/tests/test_text_label.py @@ -5,7 +5,7 @@ from model_mommy import mommy from labels.models import TextLabel -from projects.models import SEQ2SEQ +from projects.models import ProjectType from projects.tests.utils import prepare_project @@ -14,7 +14,7 @@ class TestTextLabeling(abc.ABC, TestCase): @classmethod def setUpTestData(cls): - cls.project = prepare_project(SEQ2SEQ, collaborative_annotation=cls.collaborative) + cls.project = prepare_project(ProjectType.SEQ2SEQ, collaborative_annotation=cls.collaborative) cls.example = mommy.make("Example", project=cls.project.item) cls.user = cls.project.admin cls.another_user = cls.project.approver diff --git a/backend/labels/tests/test_views.py b/backend/labels/tests/test_views.py index 98fe93c891..77ec14394e 100644 --- a/backend/labels/tests/test_views.py +++ b/backend/labels/tests/test_views.py @@ -9,20 +9,14 @@ from examples.tests.utils import make_doc from label_types.tests.utils import make_label from labels.models import BoundingBox, Category, Segmentation, Span, TextLabel -from projects.models import ( - BOUNDING_BOX, - DOCUMENT_CLASSIFICATION, - SEGMENTATION, - SEQ2SEQ, - SEQUENCE_LABELING, -) +from projects.models import ProjectType from projects.tests.utils import prepare_project from users.tests.utils import make_user class TestLabelList: model = Category - task = DOCUMENT_CLASSIFICATION + task = ProjectType.DOCUMENT_CLASSIFICATION view_name = "annotation_list" @classmethod @@ -57,13 +51,13 @@ def test_allows_project_member_to_bulk_delete_annotation(self): class TestCategoryList(TestLabelList, CRUDMixin): model = Category - task = DOCUMENT_CLASSIFICATION + task = ProjectType.DOCUMENT_CLASSIFICATION view_name = "category_list" class TestSpanList(TestLabelList, CRUDMixin): model = Span - task = SEQUENCE_LABELING + task = ProjectType.SEQUENCE_LABELING view_name = "span_list" @classmethod @@ -73,7 +67,7 @@ def make_annotation(cls, doc, member): class TestBBoxList(TestLabelList, CRUDMixin): model = BoundingBox - task = BOUNDING_BOX + task = ProjectType.BOUNDING_BOX view_name = "bbox_list" @classmethod @@ -83,7 +77,7 @@ def make_annotation(cls, doc, member): class TestSegmentationList(TestLabelList, CRUDMixin): model = Segmentation - task = SEGMENTATION + task = ProjectType.SEGMENTATION view_name = "segmentation_list" @classmethod @@ -93,13 +87,13 @@ def make_annotation(cls, doc, member): class TestTextList(TestLabelList, CRUDMixin): model = TextLabel - task = SEQ2SEQ + task = ProjectType.SEQ2SEQ view_name = "text_list" class TestSharedLabelList: model = Category - task = DOCUMENT_CLASSIFICATION + task = ProjectType.DOCUMENT_CLASSIFICATION view_name = "annotation_list" @classmethod @@ -127,13 +121,13 @@ def test_allows_project_member_to_bulk_delete_annotation(self): class TestSharedCategoryList(TestSharedLabelList, CRUDMixin): model = Category - task = DOCUMENT_CLASSIFICATION + task = ProjectType.DOCUMENT_CLASSIFICATION view_name = "category_list" class TestSharedSpanList(TestSharedLabelList, CRUDMixin): model = Span - task = SEQUENCE_LABELING + task = ProjectType.SEQUENCE_LABELING view_name = "span_list" start_offset = 0 @@ -145,12 +139,12 @@ def make_annotation(cls, doc, member): class TestSharedTextList(TestSharedLabelList, CRUDMixin): model = TextLabel - task = SEQ2SEQ + task = ProjectType.SEQ2SEQ view_name = "text_list" class TestDataLabeling: - task = DOCUMENT_CLASSIFICATION + task = ProjectType.DOCUMENT_CLASSIFICATION view_name = "annotation_list" def setUp(self): @@ -180,7 +174,7 @@ class TestCategoryCreation(TestDataLabeling, CRUDMixin): class TestSpanCreation(TestDataLabeling, CRUDMixin): - task = SEQUENCE_LABELING + task = ProjectType.SEQUENCE_LABELING view_name = "span_list" def create_data(self): @@ -189,7 +183,7 @@ def create_data(self): class TestRelationCreation(TestDataLabeling, CRUDMixin): - task = SEQUENCE_LABELING + task = ProjectType.SEQUENCE_LABELING view_name = "relation_list" def create_data(self): @@ -200,7 +194,7 @@ def create_data(self): class TestTextLabelCreation(TestDataLabeling, CRUDMixin): - task = SEQ2SEQ + task = ProjectType.SEQ2SEQ view_name = "text_list" def create_data(self): @@ -208,7 +202,7 @@ def create_data(self): class TestBoundingBoxCreation(TestDataLabeling, CRUDMixin): - task = BOUNDING_BOX + task = ProjectType.BOUNDING_BOX view_name = "bbox_list" def create_data(self): @@ -222,7 +216,7 @@ def test_allows_project_member_to_annotate(self): class TestSegmentationCreation(TestDataLabeling, CRUDMixin): - task = SEGMENTATION + task = ProjectType.SEGMENTATION view_name = "segmentation_list" def create_data(self): @@ -236,7 +230,7 @@ def test_allows_project_member_to_annotate(self): class TestLabelDetail: - task = SEQUENCE_LABELING + task = ProjectType.SEQUENCE_LABELING view_name = "annotation_detail" def setUp(self): @@ -286,7 +280,7 @@ def test_denies_non_project_member_to_delete_annotation(self): class TestCategoryDetail(TestLabelDetail, CRUDMixin): - task = DOCUMENT_CLASSIFICATION + task = ProjectType.DOCUMENT_CLASSIFICATION view_name = "category_detail" def create_annotation_data(self, doc): @@ -294,12 +288,12 @@ def create_annotation_data(self, doc): class TestSpanDetail(TestLabelDetail, CRUDMixin): - task = SEQUENCE_LABELING + task = ProjectType.SEQUENCE_LABELING view_name = "span_detail" class TestTextDetail(TestLabelDetail, CRUDMixin): - task = SEQ2SEQ + task = ProjectType.SEQ2SEQ view_name = "text_detail" def setUp(self): @@ -311,7 +305,7 @@ def create_annotation_data(self, doc): class TestBBoxDetail(TestLabelDetail, CRUDMixin): - task = BOUNDING_BOX + task = ProjectType.BOUNDING_BOX view_name = "bbox_detail" def create_annotation_data(self, doc): @@ -319,7 +313,7 @@ def create_annotation_data(self, doc): class TestSegmentationDetail(TestLabelDetail, CRUDMixin): - task = SEGMENTATION + task = ProjectType.SEGMENTATION view_name = "segmentation_detail" def create_annotation_data(self, doc): @@ -327,7 +321,7 @@ def create_annotation_data(self, doc): class TestSharedLabelDetail: - task = DOCUMENT_CLASSIFICATION + task = ProjectType.DOCUMENT_CLASSIFICATION view_name = "annotation_detail" def setUp(self): @@ -358,7 +352,7 @@ class TestSharedCategoryDetail(TestSharedLabelDetail, CRUDMixin): class TestSharedSpanDetail(TestSharedLabelDetail, CRUDMixin): - task = SEQUENCE_LABELING + task = ProjectType.SEQUENCE_LABELING view_name = "span_detail" def make_annotation(self, doc, member): @@ -366,7 +360,7 @@ def make_annotation(self, doc, member): class TestSharedTextDetail(TestSharedLabelDetail, CRUDMixin): - task = SEQ2SEQ + task = ProjectType.SEQ2SEQ view_name = "text_detail" def setUp(self): diff --git a/backend/labels/tests/utils.py b/backend/labels/tests/utils.py index 00908a6d9b..2bfe530117 100644 --- a/backend/labels/tests/utils.py +++ b/backend/labels/tests/utils.py @@ -1,18 +1,13 @@ from model_mommy import mommy -from projects.models import ( - DOCUMENT_CLASSIFICATION, - SEQ2SEQ, - SEQUENCE_LABELING, - SPEECH2TEXT, -) +from projects.models import ProjectType def make_annotation(task, doc, user, **kwargs): annotation_model = { - DOCUMENT_CLASSIFICATION: "Category", - SEQUENCE_LABELING: "Span", - SEQ2SEQ: "TextLabel", - SPEECH2TEXT: "TextLabel", + ProjectType.DOCUMENT_CLASSIFICATION: "Category", + ProjectType.SEQUENCE_LABELING: "Span", + ProjectType.SEQ2SEQ: "TextLabel", + ProjectType.SPEECH2TEXT: "TextLabel", }.get(task) return mommy.make(annotation_model, example=doc, user=user, **kwargs) diff --git a/backend/metrics/tests.py b/backend/metrics/tests.py index eadad24be5..78c0108992 100644 --- a/backend/metrics/tests.py +++ b/backend/metrics/tests.py @@ -5,13 +5,13 @@ from api.tests.utils import CRUDMixin from examples.tests.utils import make_doc from label_types.tests.utils import make_label -from projects.models import DOCUMENT_CLASSIFICATION +from projects.models import Member, ProjectType from projects.tests.utils import prepare_project class TestMemberProgress(CRUDMixin): def setUp(self): - self.project = prepare_project(DOCUMENT_CLASSIFICATION) + self.project = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION) self.example = make_doc(self.project.item) self.url = reverse(viewname="member_progress", args=[self.project.item.id]) @@ -32,7 +32,9 @@ class TestProgressHelper(CRUDMixin): collaborative_annotation = False def setUp(self): - self.project = prepare_project(DOCUMENT_CLASSIFICATION, collaborative_annotation=self.collaborative_annotation) + self.project = prepare_project( + ProjectType.DOCUMENT_CLASSIFICATION, collaborative_annotation=self.collaborative_annotation + ) self.example = make_doc(self.project.item) mommy.make("ExampleState", example=self.example, confirmed_by=self.project.admin) self.url = reverse(viewname="progress", args=[self.project.item.id]) @@ -65,7 +67,7 @@ def test_fetch_progress(self): class TestCategoryDistribution(CRUDMixin): def setUp(self): - self.project = prepare_project(DOCUMENT_CLASSIFICATION) + self.project = prepare_project(ProjectType.DOCUMENT_CLASSIFICATION) self.example = make_doc(self.project.item) self.label = make_label(self.project.item, text="label") mommy.make("Category", example=self.example, label=self.label, user=self.project.admin) @@ -76,3 +78,17 @@ def test_fetch_distribution(self): expected = {member.username: {self.label.text: 0} for member in self.project.members} expected[self.project.admin.username][self.label.text] = 1 self.assertEqual(response.data, expected) + + def test_fetch_distribution_with_removed_user(self): + # Create a category by annotator + mommy.make("Category", example=self.example, label=self.label, user=self.project.annotator) + # Remove the annotator from the project + Member.objects.filter(user=self.project.annotator, project=self.project.item).delete() + # Should not raise KeyError + response = self.assert_fetch(self.project.admin, status.HTTP_200_OK) + # The response should only include current members (after removal) + current_members = Member.objects.filter(project=self.project.item).select_related("user") + expected = {member.user.username: {self.label.text: 0} for member in current_members} + expected[self.project.admin.username][self.label.text] = 1 + # The removed user's annotations should not be in the distribution + self.assertEqual(response.data, expected) diff --git a/backend/poetry.lock b/backend/poetry.lock index 61e7b715f6..2cceb43862 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -1,32 +1,57 @@ +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. + [[package]] name = "amqp" -version = "5.0.9" +version = "5.3.1" description = "Low-level AMQP client for Python (fork of amqplib)." -category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "amqp-5.3.1-py3-none-any.whl", hash = "sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2"}, + {file = "amqp-5.3.1.tar.gz", hash = "sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432"}, +] [package.dependencies] -vine = "5.0.0" +vine = ">=5.0.0,<6.0.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 = "asgiref" -version = "3.5.0" +version = "3.11.0" description = "ASGI specs, helper code, and adapters" -category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +files = [ + {file = "asgiref-3.11.0-py3-none-any.whl", hash = "sha256:1db9021efadb0d9512ce8ffaf72fcef601c7b73a8807a1bb2ef143dc6b14846d"}, + {file = "asgiref-3.11.0.tar.gz", hash = "sha256:13acff32519542a1736223fb79a715acdebe24286d98e8b164a73085f40da2c4"}, +] + +[package.dependencies] +typing_extensions = {version = ">=4", markers = "python_version < \"3.11\""} [package.extras] -tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] +tests = ["mypy (>=1.14.0)", "pytest", "pytest-asyncio"] [[package]] name = "auto-labeling-pipeline" -version = "0.1.21" +version = "0.1.23" description = "Auto labeling pipeline for doccano" -category = "main" optional = false python-versions = "*" +files = [ + {file = "auto-labeling-pipeline-0.1.23.tar.gz", hash = "sha256:8a0f15e275bda0c1f5cadd24bb58ba447f5593b38eb4eee6d18d420eca2c944c"}, + {file = "auto_labeling_pipeline-0.1.23-py3-none-any.whl", hash = "sha256:5760be304c87440f62ef73e3420a8b3ac4cae6e07a63230115c7b90408ec3104"}, +] [package.dependencies] boto3 = "*" @@ -38,352 +63,811 @@ requests = "*" name = "autopep8" version = "1.6.0" description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "autopep8-1.6.0-py2.py3-none-any.whl", hash = "sha256:ed77137193bbac52d029a52c59bec1b0629b5a186c495f1eb21b126ac466083f"}, + {file = "autopep8-1.6.0.tar.gz", hash = "sha256:44f0932855039d2c15c4510d6df665e4730f2b8582704fa48f9c55bd3e17d979"}, +] [package.dependencies] pycodestyle = ">=2.8.0" toml = "*" [[package]] -name = "backports.zoneinfo" -version = "0.2.1" -description = "Backport of the standard library zoneinfo module" -category = "main" -optional = false -python-versions = ">=3.6" - -[package.extras] -tzdata = ["tzdata"] +name = "backports-datetime-fromisoformat" +version = "2.0.3" +description = "Backport of Python 3.11's datetime.fromisoformat" +optional = false +python-versions = ">3" +files = [ + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f681f638f10588fa3c101ee9ae2b63d3734713202ddfcfb6ec6cea0778a29d4"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:cd681460e9142f1249408e5aee6d178c6d89b49e06d44913c8fdfb6defda8d1c"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:ee68bc8735ae5058695b76d3bb2aee1d137c052a11c8303f1e966aa23b72b65b"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8273fe7932db65d952a43e238318966eab9e49e8dd546550a41df12175cc2be4"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39d57ea50aa5a524bb239688adc1d1d824c31b6094ebd39aa164d6cadb85de22"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ac6272f87693e78209dc72e84cf9ab58052027733cd0721c55356d3c881791cf"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:44c497a71f80cd2bcfc26faae8857cf8e79388e3d5fbf79d2354b8c360547d58"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:6335a4c9e8af329cb1ded5ab41a666e1448116161905a94e054f205aa6d263bc"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2e4b66e017253cdbe5a1de49e0eecff3f66cd72bcb1229d7db6e6b1832c0443"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:43e2d648e150777e13bbc2549cc960373e37bf65bd8a5d2e0cef40e16e5d8dd0"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:4ce6326fd86d5bae37813c7bf1543bae9e4c215ec6f5afe4c518be2635e2e005"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7c8fac333bf860208fd522a5394369ee3c790d0aa4311f515fcc4b6c5ef8d75"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24a4da5ab3aa0cc293dc0662a0c6d1da1a011dc1edcbc3122a288cfed13a0b45"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:58ea11e3bf912bd0a36b0519eae2c5b560b3cb972ea756e66b73fb9be460af01"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8a375c7dbee4734318714a799b6c697223e4bbb57232af37fbfff88fb48a14c6"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:ac677b1664c4585c2e014739f6678137c8336815406052349c85898206ec7061"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:66ce47ee1ba91e146149cf40565c3d750ea1be94faf660ca733d8601e0848147"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:8b7e069910a66b3bba61df35b5f879e5253ff0821a70375b9daf06444d046fa4"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:a3b5d1d04a9e0f7b15aa1e647c750631a873b298cdd1255687bb68779fe8eb35"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec1b95986430e789c076610aea704db20874f0781b8624f648ca9fb6ef67c6e1"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffe5f793db59e2f1d45ec35a1cf51404fdd69df9f6952a0c87c3060af4c00e32"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:620e8e73bd2595dfff1b4d256a12b67fce90ece3de87b38e1dde46b910f46f4d"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4cf9c0a985d68476c1cabd6385c691201dda2337d7453fb4da9679ce9f23f4e7"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:d144868a73002e6e2e6fef72333e7b0129cecdd121aa8f1edba7107fd067255d"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e81b26497a17c29595bc7df20bc6a872ceea5f8c9d6537283945d4b6396aec10"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:5ba00ead8d9d82fd6123eb4891c566d30a293454e54e32ff7ead7644f5f7e575"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:24d574cb4072e1640b00864e94c4c89858033936ece3fc0e1c6f7179f120d0a8"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9735695a66aad654500b0193525e590c693ab3368478ce07b34b443a1ea5e824"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63d39709e17eb72685d052ac82acf0763e047f57c86af1b791505b1fec96915d"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:1ea2cc84224937d6b9b4c07f5cb7c667f2bde28c255645ba27f8a675a7af8234"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4024e6d35a9fdc1b3fd6ac7a673bd16cb176c7e0b952af6428b7129a70f72cce"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5e2dcc94dc9c9ab8704409d86fcb5236316e9dcef6feed8162287634e3568f4c"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fa2de871801d824c255fac7e5e7e50f2be6c9c376fd9268b40c54b5e9da91f42"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:1314d4923c1509aa9696712a7bc0c7160d3b7acf72adafbbe6c558d523f5d491"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:b750ecba3a8815ad8bc48311552f3f8ab99dd2326d29df7ff670d9c49321f48f"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d5117dce805d8a2f78baeddc8c6127281fa0a5e2c40c6dd992ba6b2b367876"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb35f607bd1cbe37b896379d5f5ed4dc298b536f4b959cb63180e05cacc0539d"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:61c74710900602637d2d145dda9720c94e303380803bf68811b2a151deec75c2"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ece59af54ebf67ecbfbbf3ca9066f5687879e36527ad69d8b6e3ac565d565a62"}, + {file = "backports_datetime_fromisoformat-2.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:d0a7c5f875068efe106f62233bc712d50db4d07c13c7db570175c7857a7b5dbd"}, + {file = "backports_datetime_fromisoformat-2.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90e202e72a3d5aae673fcc8c9a4267d56b2f532beeb9173361293625fe4d2039"}, + {file = "backports_datetime_fromisoformat-2.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2df98ef1b76f5a58bb493dda552259ba60c3a37557d848e039524203951c9f06"}, + {file = "backports_datetime_fromisoformat-2.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7100adcda5e818b5a894ad0626e38118bb896a347f40ebed8981155675b9ba7b"}, + {file = "backports_datetime_fromisoformat-2.0.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e410383f5d6a449a529d074e88af8bc80020bb42b402265f9c02c8358c11da5"}, + {file = "backports_datetime_fromisoformat-2.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2797593760da6bcc32c4a13fa825af183cd4bfd333c60b3dbf84711afca26ef"}, + {file = "backports_datetime_fromisoformat-2.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35a144fd681a0bea1013ccc4cd3fd4dc758ea17ee23dca019c02b82ec46fc0c4"}, + {file = "backports_datetime_fromisoformat-2.0.3.tar.gz", hash = "sha256:b58edc8f517b66b397abc250ecc737969486703a66eb97e01e6d51291b1a139d"}, +] [[package]] name = "billiard" -version = "3.6.4.0" +version = "4.2.4" description = "Python multiprocessing fork with improvements and bugfixes" -category = "main" optional = false -python-versions = "*" +python-versions = ">=3.7" +files = [ + {file = "billiard-4.2.4-py3-none-any.whl", hash = "sha256:525b42bdec68d2b983347ac312f892db930858495db601b5836ac24e6477cde5"}, + {file = "billiard-4.2.4.tar.gz", hash = "sha256:55f542c371209e03cd5862299b74e52e4fbcba8250ba611ad94276b369b6a85f"}, +] [[package]] name = "black" -version = "22.1.0" +version = "25.12.0" description = "The uncompromising code formatter." -category = "dev" optional = false -python-versions = ">=3.6.2" +python-versions = ">=3.10" +files = [ + {file = "black-25.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f85ba1ad15d446756b4ab5f3044731bf68b777f8f9ac9cdabd2425b97cd9c4e8"}, + {file = "black-25.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:546eecfe9a3a6b46f9d69d8a642585a6eaf348bcbbc4d87a19635570e02d9f4a"}, + {file = "black-25.12.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17dcc893da8d73d8f74a596f64b7c98ef5239c2cd2b053c0f25912c4494bf9ea"}, + {file = "black-25.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:09524b0e6af8ba7a3ffabdfc7a9922fb9adef60fed008c7cd2fc01f3048e6e6f"}, + {file = "black-25.12.0-cp310-cp310-win_arm64.whl", hash = "sha256:b162653ed89eb942758efeb29d5e333ca5bb90e5130216f8369857db5955a7da"}, + {file = "black-25.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0cfa263e85caea2cff57d8f917f9f51adae8e20b610e2b23de35b5b11ce691a"}, + {file = "black-25.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a2f578ae20c19c50a382286ba78bfbeafdf788579b053d8e4980afb079ab9be"}, + {file = "black-25.12.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e1b65634b0e471d07ff86ec338819e2ef860689859ef4501ab7ac290431f9b"}, + {file = "black-25.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:a3fa71e3b8dd9f7c6ac4d818345237dfb4175ed3bf37cd5a581dbc4c034f1ec5"}, + {file = "black-25.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:51e267458f7e650afed8445dc7edb3187143003d52a1b710c7321aef22aa9655"}, + {file = "black-25.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:31f96b7c98c1ddaeb07dc0f56c652e25bdedaac76d5b68a059d998b57c55594a"}, + {file = "black-25.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05dd459a19e218078a1f98178c13f861fe6a9a5f88fc969ca4d9b49eb1809783"}, + {file = "black-25.12.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1f68c5eff61f226934be6b5b80296cf6939e5d2f0c2f7d543ea08b204bfaf59"}, + {file = "black-25.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:274f940c147ddab4442d316b27f9e332ca586d39c85ecf59ebdea82cc9ee8892"}, + {file = "black-25.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:169506ba91ef21e2e0591563deda7f00030cb466e747c4b09cb0a9dae5db2f43"}, + {file = "black-25.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a05ddeb656534c3e27a05a29196c962877c83fa5503db89e68857d1161ad08a5"}, + {file = "black-25.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9ec77439ef3e34896995503865a85732c94396edcc739f302c5673a2315e1e7f"}, + {file = "black-25.12.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e509c858adf63aa61d908061b52e580c40eae0dfa72415fa47ac01b12e29baf"}, + {file = "black-25.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:252678f07f5bac4ff0d0e9b261fbb029fa530cfa206d0a636a34ab445ef8ca9d"}, + {file = "black-25.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bc5b1c09fe3c931ddd20ee548511c64ebf964ada7e6f0763d443947fd1c603ce"}, + {file = "black-25.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:0a0953b134f9335c2434864a643c842c44fba562155c738a2a37a4d61f00cad5"}, + {file = "black-25.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2355bbb6c3b76062870942d8cc450d4f8ac71f9c93c40122762c8784df49543f"}, + {file = "black-25.12.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9678bd991cc793e81d19aeeae57966ee02909877cb65838ccffef24c3ebac08f"}, + {file = "black-25.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:97596189949a8aad13ad12fcbb4ae89330039b96ad6742e6f6b45e75ad5cfd83"}, + {file = "black-25.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:778285d9ea197f34704e3791ea9404cd6d07595745907dd2ce3da7a13627b29b"}, + {file = "black-25.12.0-py3-none-any.whl", hash = "sha256:48ceb36c16dbc84062740049eef990bb2ce07598272e673c17d1a7720c71c828"}, + {file = "black-25.12.0.tar.gz", hash = "sha256:8d3dd9cea14bff7ddc0eb243c811cdb1a011ebb4800a5f0335a01a68654796a7"}, +] [package.dependencies] click = ">=8.0.0" mypy-extensions = ">=0.4.3" +packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" -tomli = ">=1.1.0" -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} +pytokens = ">=0.3.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] +d = ["aiohttp (>=3.10)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "boto3" -version = "1.21.1" +version = "1.42.25" description = "The AWS SDK for Python" -category = "main" optional = false -python-versions = ">= 3.6" +python-versions = ">=3.9" +files = [ + {file = "boto3-1.42.25-py3-none-any.whl", hash = "sha256:8128bde4f9d5ffce129c76d1a2efe220e3af967a2ad30bc305ba088bbc96343d"}, + {file = "boto3-1.42.25.tar.gz", hash = "sha256:ccb5e757dd62698d25766cc54cf5c47bea43287efa59c93cf1df8c8fbc26eeda"}, +] [package.dependencies] -botocore = ">=1.24.1,<1.25.0" -jmespath = ">=0.7.1,<1.0.0" -s3transfer = ">=0.5.0,<0.6.0" +botocore = ">=1.42.25,<1.43.0" +jmespath = ">=0.7.1,<2.0.0" +s3transfer = ">=0.16.0,<0.17.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.24.1" +version = "1.42.25" description = "Low-level, data-driven core of boto 3." -category = "main" optional = false -python-versions = ">= 3.6" +python-versions = ">=3.9" +files = [ + {file = "botocore-1.42.25-py3-none-any.whl", hash = "sha256:470261966aab1d09a1cd4ba56810098834443602846559ba9504f6613dfa52dc"}, + {file = "botocore-1.42.25.tar.gz", hash = "sha256:7ae79d1f77d3771e83e4dd46bce43166a1ba85d58a49cffe4c4a721418616054"}, +] [package.dependencies] -jmespath = ">=0.7.1,<1.0.0" +jmespath = ">=0.7.1,<2.0.0" python-dateutil = ">=2.1,<3.0.0" -urllib3 = ">=1.25.4,<1.27" +urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} [package.extras] -crt = ["awscrt (==0.12.5)"] - -[[package]] -name = "cachetools" -version = "5.0.0" -description = "Extensible memoizing collections and decorators" -category = "main" -optional = false -python-versions = "~=3.7" +crt = ["awscrt (==0.29.2)"] [[package]] name = "celery" -version = "5.2.3" +version = "5.6.2" description = "Distributed Task Queue." -category = "main" optional = false -python-versions = ">=3.7," +python-versions = ">=3.9" +files = [ + {file = "celery-5.6.2-py3-none-any.whl", hash = "sha256:3ffafacbe056951b629c7abcf9064c4a2366de0bdfc9fdba421b97ebb68619a5"}, + {file = "celery-5.6.2.tar.gz", hash = "sha256:4a8921c3fcf2ad76317d3b29020772103581ed2454c4c042cc55dcc43585009b"}, +] [package.dependencies] -billiard = ">=3.6.4.0,<4.0" -click = ">=8.0.3,<9.0" -click-didyoumean = ">=0.0.3" +billiard = ">=4.2.1,<5.0" +click = ">=8.1.2,<9.0" +click-didyoumean = ">=0.3.0" click-plugins = ">=1.1.1" click-repl = ">=0.2.0" -kombu = ">=5.2.3,<6.0" -pytz = ">=2021.3" -vine = ">=5.0.0,<6.0" +exceptiongroup = {version = ">=1.3.0", markers = "python_version < \"3.11\""} +kombu = ">=5.6.0" +python-dateutil = ">=2.8.2" +tzlocal = "*" +vine = ">=5.1.0,<6.0" [package.extras] -arangodb = ["pyArango (>=1.3.2)"] -auth = ["cryptography"] -azureblockblob = ["azure-storage-blob (==12.9.0)"] +arangodb = ["pyArango (>=2.0.2)"] +auth = ["cryptography (==46.0.3)"] +azureblockblob = ["azure-identity (>=1.19.0)", "azure-storage-blob (>=12.15.0)"] brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"] -cassandra = ["cassandra-driver (<3.21.0)"] -consul = ["python-consul2"] -cosmosdbsql = ["pydocumentdb (==2.3.2)"] +cassandra = ["cassandra-driver (>=3.25.0,<4)"] +consul = ["python-consul2 (==0.1.5)"] +cosmosdbsql = ["pydocumentdb (==2.3.5)"] couchbase = ["couchbase (>=3.0.0)"] -couchdb = ["pycouchdb"] -django = ["Django (>=1.11)"] -dynamodb = ["boto3 (>=1.9.178)"] -elasticsearch = ["elasticsearch"] +couchdb = ["pycouchdb (==1.16.0)"] +django = ["Django (>=2.2.28)"] +dynamodb = ["boto3 (>=1.26.143)"] +elasticsearch = ["elastic-transport (<=9.1.0)", "elasticsearch (<=9.1.2)"] eventlet = ["eventlet (>=0.32.0)"] +gcs = ["google-cloud-firestore (==2.22.0)", "google-cloud-storage (>=2.10.0)", "grpcio (==1.75.1)"] gevent = ["gevent (>=1.5.0)"] -librabbitmq = ["librabbitmq (>=1.5.0)"] -memcache = ["pylibmc"] -mongodb = ["pymongo[srv] (>=3.11.1)"] -msgpack = ["msgpack"] -pymemcache = ["python-memcached"] -pyro = ["pyro4"] -pytest = ["pytest-celery"] -redis = ["redis (>=3.4.1,!=4.0.0,!=4.0.1)"] -s3 = ["boto3 (>=1.9.125)"] -slmq = ["softlayer-messaging (>=1.0.3)"] -solar = ["ephem"] -sqlalchemy = ["sqlalchemy"] -sqs = ["kombu"] -tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"] -yaml = ["PyYAML (>=3.10)"] +librabbitmq = ["librabbitmq (>=2.0.0)"] +memcache = ["pylibmc (==1.6.3)"] +mongodb = ["kombu[mongodb]"] +msgpack = ["kombu[msgpack]"] +pydantic = ["pydantic (>=2.12.0a1)", "pydantic (>=2.4)"] +pymemcache = ["python-memcached (>=1.61)"] +pyro = ["pyro4 (==4.82)"] +pytest = ["pytest-celery[all] (>=1.2.0,<1.3.0)"] +redis = ["kombu[redis]"] +s3 = ["boto3 (>=1.26.143)"] +slmq = ["softlayer_messaging (>=1.0.3)"] +solar = ["ephem (==4.2)"] +sqlalchemy = ["kombu[sqlalchemy]"] +sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.5.0)", "pycurl (>=7.43.0.5,<7.45.4)", "pycurl (>=7.45.4)", "urllib3 (>=1.26.16)"] +tblib = ["tblib (==3.2.2)"] +yaml = ["kombu[yaml]"] zookeeper = ["kazoo (>=1.3.1)"] -zstd = ["zstandard"] +zstd = ["zstandard (==0.23.0)"] [[package]] name = "certifi" -version = "2021.10.8" +version = "2026.1.4" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false -python-versions = "*" +python-versions = ">=3.7" +files = [ + {file = "certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c"}, + {file = "certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120"}, +] + +[[package]] +name = "cffi" +version = "2.0.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.9" +files = [ + {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, + {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, + {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, + {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, + {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, + {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, + {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, + {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, + {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, + {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, + {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, + {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, + {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, + {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, + {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, + {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, + {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, + {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, + {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"}, + {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"}, + {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, + {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, +] + +[package.dependencies] +pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} [[package]] name = "chardet" version = "4.0.0" description = "Universal encoding detector for Python 2 and 3" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, + {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, +] [[package]] name = "charset-normalizer" -version = "2.0.12" +version = "3.4.4" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false -python-versions = ">=3.5.0" - -[package.extras] -unicode_backport = ["unicodedata2"] +python-versions = ">=3.7" +files = [ + {file = "charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d"}, + {file = "charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016"}, + {file = "charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525"}, + {file = "charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14"}, + {file = "charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c"}, + {file = "charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ce8a0633f41a967713a59c4139d29110c07e826d131a316b50ce11b1d79b4f84"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaabd426fe94daf8fd157c32e571c85cb12e66692f15516a83a03264b08d06c3"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c4ef880e27901b6cc782f1b95f82da9313c0eb95c3af699103088fa0ac3ce9ac"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aaba3b0819274cc41757a1da876f810a3e4d7b6eb25699253a4effef9e8e4af"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:778d2e08eda00f4256d7f672ca9fef386071c9202f5e4607920b86d7803387f2"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f155a433c2ec037d4e8df17d18922c3a0d9b3232a396690f17175d2946f0218d"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a8bf8d0f749c5757af2142fe7903a9df1d2e8aa3841559b2bad34b08d0e2bcf3"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:194f08cbb32dc406d6e1aea671a68be0823673db2832b38405deba2fb0d88f63"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:6aee717dcfead04c6eb1ce3bd29ac1e22663cdea57f943c87d1eab9a025438d7"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:cd4b7ca9984e5e7985c12bc60a6f173f3c958eae74f3ef6624bb6b26e2abbae4"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:b7cf1017d601aa35e6bb650b6ad28652c9cd78ee6caff19f3c28d03e1c80acbf"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:e912091979546adf63357d7e2ccff9b44f026c075aeaf25a52d0e95ad2281074"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5cb4d72eea50c8868f5288b7f7f33ed276118325c1dfd3957089f6b519e1382a"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-win32.whl", hash = "sha256:837c2ce8c5a65a2035be9b3569c684358dfbf109fd3b6969630a87535495ceaa"}, + {file = "charset_normalizer-3.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:44c2a8734b333e0578090c4cd6b16f275e07aa6614ca8715e6c038e865e70576"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a9768c477b9d7bd54bc0c86dbaebdec6f03306675526c9927c0e8a04e8f94af9"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bee1e43c28aa63cb16e5c14e582580546b08e535299b8b6158a7c9c768a1f3d"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fd44c878ea55ba351104cb93cc85e74916eb8fa440ca7903e57575e97394f608"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0f04b14ffe5fdc8c4933862d8306109a2c51e0704acfa35d51598eb45a1e89fc"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cd09d08005f958f370f539f186d10aec3377d55b9eeb0d796025d4886119d76e"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4fe7859a4e3e8457458e2ff592f15ccb02f3da787fcd31e0183879c3ad4692a1"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fa09f53c465e532f4d3db095e0c55b615f010ad81803d383195b6b5ca6cbf5f3"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7fa17817dc5625de8a027cb8b26d9fefa3ea28c8253929b8d6649e705d2835b6"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5947809c8a2417be3267efc979c47d76a079758166f7d43ef5ae8e9f92751f88"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:4902828217069c3c5c71094537a8e623f5d097858ac6ca8252f7b4d10b7560f1"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:7c308f7e26e4363d79df40ca5b2be1c6ba9f02bdbccfed5abddb7859a6ce72cf"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c9d3c380143a1fedbff95a312aa798578371eb29da42106a29019368a475318"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cb01158d8b88ee68f15949894ccc6712278243d95f344770fa7593fa2d94410c"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-win32.whl", hash = "sha256:2677acec1a2f8ef614c6888b5b4ae4060cc184174a938ed4e8ef690e15d3e505"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:f8e160feb2aed042cd657a72acc0b481212ed28b1b9a95c0cee1621b524e1966"}, + {file = "charset_normalizer-3.4.4-cp39-cp39-win_arm64.whl", hash = "sha256:b5d84d37db046c5ca74ee7bb47dd6cbc13f80665fdde3e8040bdd3fb015ecb50"}, + {file = "charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f"}, + {file = "charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a"}, +] [[package]] name = "click" -version = "8.0.3" +version = "8.3.1" description = "Composable command line interface toolkit" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.10" +files = [ + {file = "click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6"}, + {file = "click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a"}, +] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "click-didyoumean" -version = "0.3.0" +version = "0.3.1" description = "Enables git-like *did-you-mean* feature in click" -category = "main" optional = false -python-versions = ">=3.6.2,<4.0.0" +python-versions = ">=3.6.2" +files = [ + {file = "click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c"}, + {file = "click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463"}, +] [package.dependencies] click = ">=7" [[package]] name = "click-plugins" -version = "1.1.1" +version = "1.1.1.2" description = "An extension module for click to enable registering CLI commands via setuptools entry-points." -category = "main" optional = false python-versions = "*" +files = [ + {file = "click_plugins-1.1.1.2-py2.py3-none-any.whl", hash = "sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6"}, + {file = "click_plugins-1.1.1.2.tar.gz", hash = "sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261"}, +] [package.dependencies] click = ">=4.0" [package.extras] -dev = ["pytest (>=3.6)", "pytest-cov", "wheel", "coveralls"] +dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] [[package]] name = "click-repl" -version = "0.2.0" +version = "0.3.0" description = "REPL plugin for Click" -category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6" +files = [ + {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"}, + {file = "click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812"}, +] [package.dependencies] -click = "*" -prompt-toolkit = "*" -six = "*" +click = ">=7.0" +prompt-toolkit = ">=3.0.36" + +[package.extras] +testing = ["pytest (>=7.2.1)", "pytest-cov (>=4.0.0)", "tox (>=4.4.3)"] [[package]] name = "colorama" -version = "0.4.4" +version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +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 = "coreapi" -version = "2.3.3" -description = "Python client library for Core API." -category = "main" +name = "coverage" +version = "6.5.0" +description = "Code coverage measurement for Python" optional = false -python-versions = "*" +python-versions = ">=3.7" +files = [ + {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, + {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"}, + {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"}, + {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"}, + {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"}, + {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"}, + {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"}, + {file = "coverage-6.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f"}, + {file = "coverage-6.5.0-cp37-cp37m-win32.whl", hash = "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b"}, + {file = "coverage-6.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2"}, + {file = "coverage-6.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c"}, + {file = "coverage-6.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e"}, + {file = "coverage-6.5.0-cp38-cp38-win32.whl", hash = "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d"}, + {file = "coverage-6.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6"}, + {file = "coverage-6.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745"}, + {file = "coverage-6.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f"}, + {file = "coverage-6.5.0-cp39-cp39-win32.whl", hash = "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72"}, + {file = "coverage-6.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"}, + {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"}, + {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, +] -[package.dependencies] -coreschema = "*" -itypes = "*" -requests = "*" -uritemplate = "*" +[package.extras] +toml = ["tomli"] [[package]] -name = "coreschema" -version = "0.0.4" -description = "Core Schema." -category = "main" -optional = false -python-versions = "*" +name = "cryptography" +version = "46.0.3" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = "!=3.9.0,!=3.9.1,>=3.8" +files = [ + {file = "cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a"}, + {file = "cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc"}, + {file = "cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d"}, + {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb"}, + {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849"}, + {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8"}, + {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec"}, + {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91"}, + {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e"}, + {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926"}, + {file = "cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71"}, + {file = "cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac"}, + {file = "cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018"}, + {file = "cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb"}, + {file = "cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c"}, + {file = "cryptography-46.0.3-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:00a5e7e87938e5ff9ff5447ab086a5706a957137e6e433841e9d24f38a065217"}, + {file = "cryptography-46.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c8daeb2d2174beb4575b77482320303f3d39b8e81153da4f0fb08eb5fe86a6c5"}, + {file = "cryptography-46.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:39b6755623145ad5eff1dab323f4eae2a32a77a7abef2c5089a04a3d04366715"}, + {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:db391fa7c66df6762ee3f00c95a89e6d428f4d60e7abc8328f4fe155b5ac6e54"}, + {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:78a97cf6a8839a48c49271cdcbd5cf37ca2c1d6b7fdd86cc864f302b5e9bf459"}, + {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:dfb781ff7eaa91a6f7fd41776ec37c5853c795d3b358d4896fdbb5df168af422"}, + {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:6f61efb26e76c45c4a227835ddeae96d83624fb0d29eb5df5b96e14ed1a0afb7"}, + {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:23b1a8f26e43f47ceb6d6a43115f33a5a37d57df4ea0ca295b780ae8546e8044"}, + {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:b419ae593c86b87014b9be7396b385491ad7f320bde96826d0dd174459e54665"}, + {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:50fc3343ac490c6b08c0cf0d704e881d0d660be923fd3076db3e932007e726e3"}, + {file = "cryptography-46.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22d7e97932f511d6b0b04f2bfd818d73dcd5928db509460aaf48384778eb6d20"}, + {file = "cryptography-46.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d55f3dffadd674514ad19451161118fd010988540cee43d8bc20675e775925de"}, + {file = "cryptography-46.0.3-cp314-cp314t-win32.whl", hash = "sha256:8a6e050cb6164d3f830453754094c086ff2d0b2f3a897a1d9820f6139a1f0914"}, + {file = "cryptography-46.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:760f83faa07f8b64e9c33fc963d790a2edb24efb479e3520c14a45741cd9b2db"}, + {file = "cryptography-46.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:516ea134e703e9fe26bcd1277a4b59ad30586ea90c365a87781d7887a646fe21"}, + {file = "cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936"}, + {file = "cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683"}, + {file = "cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d"}, + {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0"}, + {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc"}, + {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3"}, + {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971"}, + {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac"}, + {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04"}, + {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506"}, + {file = "cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963"}, + {file = "cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4"}, + {file = "cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df"}, + {file = "cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f"}, + {file = "cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372"}, + {file = "cryptography-46.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a23582810fedb8c0bc47524558fb6c56aac3fc252cb306072fd2815da2a47c32"}, + {file = "cryptography-46.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e7aec276d68421f9574040c26e2a7c3771060bc0cff408bae1dcb19d3ab1e63c"}, + {file = "cryptography-46.0.3-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7ce938a99998ed3c8aa7e7272dca1a610401ede816d36d0693907d863b10d9ea"}, + {file = "cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:191bb60a7be5e6f54e30ba16fdfae78ad3a342a0599eb4193ba88e3f3d6e185b"}, + {file = "cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c70cc23f12726be8f8bc72e41d5065d77e4515efae3690326764ea1b07845cfb"}, + {file = "cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:9394673a9f4de09e28b5356e7fff97d778f8abad85c9d5ac4a4b7e25a0de7717"}, + {file = "cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:94cd0549accc38d1494e1f8de71eca837d0509d0d44bf11d158524b0e12cebf9"}, + {file = "cryptography-46.0.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6b5063083824e5509fdba180721d55909ffacccc8adbec85268b48439423d78c"}, + {file = "cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1"}, +] [package.dependencies] -jinja2 = "*" - -[[package]] -name = "coverage" -version = "6.3.1" -description = "Code coverage measurement for Python" -category = "dev" -optional = false -python-versions = ">=3.7" +cffi = {version = ">=2.0.0", markers = "python_full_version >= \"3.9\" and platform_python_implementation != \"PyPy\""} +typing-extensions = {version = ">=4.13.2", markers = "python_full_version < \"3.11\""} [package.extras] -toml = ["tomli"] +docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs", "sphinx-rtd-theme (>=3.0.0)"] +docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] +nox = ["nox[uv] (>=2024.4.15)"] +pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"] +sdist = ["build (>=1.0.0)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi (>=2024)", "cryptography-vectors (==46.0.3)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test-randomorder = ["pytest-randomly"] [[package]] name = "defusedxml" version = "0.7.1" description = "XML bomb protection for Python stdlib modules" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] [[package]] name = "dj-database-url" version = "0.5.0" description = "Use Database URLs in your Django Application." -category = "main" optional = false python-versions = "*" +files = [ + {file = "dj-database-url-0.5.0.tar.gz", hash = "sha256:4aeaeb1f573c74835b0686a2b46b85990571159ffc21aa57ecd4d1e1cb334163"}, + {file = "dj_database_url-0.5.0-py2.py3-none-any.whl", hash = "sha256:851785365761ebe4994a921b433062309eb882fedd318e1b0fcecc607ed02da9"}, +] [[package]] name = "dj-rest-auth" -version = "2.2.3" +version = "2.2.8" description = "Authentication and Registration in Django Rest Framework" -category = "main" optional = false python-versions = ">=3.5" +files = [ + {file = "dj-rest-auth-2.2.8.tar.gz", hash = "sha256:9fb3492888185ede8b2064ad6803120c7b0b83ab08e2347a02e9b44282374242"}, +] [package.dependencies] Django = ">=2.0" +django-allauth = {version = ">=0.40.0,<0.53.0", optional = true, markers = "extra == \"with_social\""} djangorestframework = ">=3.7.0" [package.extras] -with_social = ["django-allauth (>=0.40.0,<0.48.0)"] +with-social = ["django-allauth (>=0.40.0,<0.53.0)"] [[package]] name = "django" -version = "4.0.6" +version = "4.2.27" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." -category = "main" optional = false python-versions = ">=3.8" +files = [ + {file = "django-4.2.27-py3-none-any.whl", hash = "sha256:f393a394053713e7d213984555c5b7d3caeee78b2ccb729888a0774dff6c11a8"}, + {file = "django-4.2.27.tar.gz", hash = "sha256:b865fbe0f4a3d1ee36594c5efa42b20db3c8bbb10dff0736face1c6e4bda5b92"}, +] [package.dependencies] -asgiref = ">=3.4.1,<4" -"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} -sqlparse = ">=0.2.2" +asgiref = ">=3.6.0,<4" +sqlparse = ">=0.3.1" tzdata = {version = "*", markers = "sys_platform == \"win32\""} [package.extras] argon2 = ["argon2-cffi (>=19.1.0)"] bcrypt = ["bcrypt"] +[[package]] +name = "django-allauth" +version = "0.52.0" +description = "Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication." +optional = false +python-versions = ">=3.5" +files = [ + {file = "django-allauth-0.52.0.tar.gz", hash = "sha256:e380661ceafe55734c40102819ae720403027036f28e9f9827f0faeddc24ed5f"}, +] + +[package.dependencies] +Django = ">=2.0" +pyjwt = {version = ">=1.7", extras = ["crypto"]} +python3-openid = ">=3.0.8" +requests = "*" +requests-oauthlib = ">=0.3.0" + [[package]] name = "django-celery-results" -version = "2.2.0" +version = "2.4.0" description = "Celery result backends for Django." -category = "main" optional = false python-versions = "*" +files = [ + {file = "django_celery_results-2.4.0-py3-none-any.whl", hash = "sha256:be91307c02fbbf0dda21993c3001c60edb74595444ccd6ad696552fe3689e85b"}, + {file = "django_celery_results-2.4.0.tar.gz", hash = "sha256:75aa51970db5691cbf242c6a0ff50c8cdf419e265cd0e9b772335d06436c4b99"}, +] [package.dependencies] -celery = ">=5.0,<6.0" +celery = ">=5.2.3,<6.0" [[package]] name = "django-cleanup" version = "6.0.0" description = "Deletes old files." -category = "main" optional = false python-versions = "*" +files = [ + {file = "django-cleanup-6.0.0.tar.gz", hash = "sha256:922e06ef8839c92bd3ab37a84db6058b8764f3fe44dbb4487bbca941d288280a"}, + {file = "django_cleanup-6.0.0-py2.py3-none-any.whl", hash = "sha256:997feab3b1f7a2e84f71c29e83b1d664459ec0d4b1924977b1fa25b5babb8703"}, +] [[package]] name = "django-cors-headers" -version = "3.11.0" +version = "3.14.0" description = "django-cors-headers is a Django application for handling the server headers required for Cross-Origin Resource Sharing (CORS)." -category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "django_cors_headers-3.14.0-py3-none-any.whl", hash = "sha256:684180013cc7277bdd8702b80a3c5a4b3fcae4abb2bf134dceb9f5dfe300228e"}, + {file = "django_cors_headers-3.14.0.tar.gz", hash = "sha256:5fbd58a6fb4119d975754b2bc090f35ec160a8373f276612c675b00e8a138739"}, +] [package.dependencies] -Django = ">=2.2" +Django = ">=3.2" [[package]] name = "django-drf-filepond" -version = "0.4.1" +version = "0.5.0" description = "Filepond server app for Django REST Framework" -category = "main" optional = false python-versions = "*" +files = [ + {file = "django-drf-filepond-0.5.0.tar.gz", hash = "sha256:360abcbcfdc016398435679dcc768b0c2d6b29a92db46fe3430ad31176251a13"}, + {file = "django_drf_filepond-0.5.0-py2.py3-none-any.whl", hash = "sha256:55d64c3272c716f0811f2e67877cc005b8927e96bb34ba7f7105202d6bd5a647"}, +] [package.dependencies] Django = {version = ">=2.2.25", markers = "python_version >= \"3.6\""} @@ -395,44 +879,56 @@ six = ">=1.14.0" [[package]] name = "django-filter" -version = "21.1" +version = "22.1" description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically." -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" +files = [ + {file = "django-filter-22.1.tar.gz", hash = "sha256:ed473b76e84f7e83b2511bb2050c3efb36d135207d0128dfe3ae4b36e3594ba5"}, + {file = "django_filter-22.1-py3-none-any.whl", hash = "sha256:ed429e34760127e3520a67f415bec4c905d4649fbe45d0d6da37e6ff5e0287eb"}, +] [package.dependencies] -Django = ">=2.2" +Django = ">=3.2" [[package]] name = "django-health-check" -version = "3.16.5" -description = "Run checks on services like databases, queue servers, celery processes, etc." -category = "main" +version = "3.20.8" +description = "Monitor the health of your Django app and its connected services." optional = false -python-versions = "*" +python-versions = ">=3.10" +files = [ + {file = "django_health_check-3.20.8-py3-none-any.whl", hash = "sha256:89f06fd3ecfefb13a8444cbc49508c76f1f49c816624026f720a28e0e67a458c"}, + {file = "django_health_check-3.20.8.tar.gz", hash = "sha256:bbb7286af4b4e2079d262eeb3e68014c8980f8fcfbd295bca1ec31cbf827b83c"}, +] [package.dependencies] -django = ">=2.2" +Django = ">=4.2" [[package]] name = "django-polymorphic" -version = "3.1.0" -description = "Seamless polymorphic inheritance for Django models" -category = "main" +version = "4.9.0" +description = "Seamless polymorphic inheritance for Django models." optional = false -python-versions = "*" +python-versions = "<4.0,>=3.10" +files = [ + {file = "django_polymorphic-4.9.0-py3-none-any.whl", hash = "sha256:ac13eb365d65ea5275f901011e80386c4147994f6879fa5138f7b92337ef8655"}, + {file = "django_polymorphic-4.9.0.tar.gz", hash = "sha256:9baaba6b4db67f148c073406dc65a52f3c693d7a60f1b62153f7cd00374f48e7"}, +] [package.dependencies] -Django = ">=2.1" +django = ">=4.2" [[package]] name = "django-rest-polymorphic" -version = "0.1.9" +version = "0.1.10" description = "Polymorphic serializers for Django REST Framework." -category = "main" optional = false python-versions = "*" +files = [ + {file = "django-rest-polymorphic-0.1.10.tar.gz", hash = "sha256:2960f58ed9a8bb0d42bc72c8ffaadfbd7f37d2573d42a1cd9a6460f3d572b519"}, + {file = "django_rest_polymorphic-0.1.10-py2.py3-none-any.whl", hash = "sha256:f3980e3e2af73357e7913f9b1410ef856866bcfcc46903b70fe9621118bb538c"}, +] [package.dependencies] django = "*" @@ -442,127 +938,189 @@ six = "*" [[package]] name = "django-storages" -version = "1.12.3" +version = "1.14.6" description = "Support for many storage backends in Django" -category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" +files = [ + {file = "django_storages-1.14.6-py3-none-any.whl", hash = "sha256:11b7b6200e1cb5ffcd9962bd3673a39c7d6a6109e8096f0e03d46fab3d3aabd9"}, + {file = "django_storages-1.14.6.tar.gz", hash = "sha256:7a25ce8f4214f69ac9c7ce87e2603887f7ae99326c316bc8d2d75375e09341c9"}, +] [package.dependencies] -Django = ">=2.2" -google-cloud-storage = {version = ">=1.27.0", optional = true, markers = "extra == \"google\""} +Django = ">=3.2" +google-cloud-storage = {version = ">=1.36.1", optional = true, markers = "extra == \"google\""} [package.extras] -azure = ["azure-storage-blob (>=12.0.0)"] +azure = ["azure-core (>=1.13)", "azure-storage-blob (>=12)"] boto3 = ["boto3 (>=1.4.4)"] dropbox = ["dropbox (>=7.2.1)"] -google = ["google-cloud-storage (>=1.27.0)"] +google = ["google-cloud-storage (>=1.36.1)"] libcloud = ["apache-libcloud"] -sftp = ["paramiko"] +s3 = ["boto3 (>=1.4.4)"] +sftp = ["paramiko (>=1.15)"] [[package]] name = "djangorestframework" -version = "3.13.1" +version = "3.16.1" description = "Web APIs for Django, made easy." -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" +files = [ + {file = "djangorestframework-3.16.1-py3-none-any.whl", hash = "sha256:33a59f47fb9c85ede792cbf88bde71893bcda0667bc573f784649521f1102cec"}, + {file = "djangorestframework-3.16.1.tar.gz", hash = "sha256:166809528b1aced0a17dc66c24492af18049f2c9420dbd0be29422029cfc3ff7"}, +] [package.dependencies] -django = ">=2.2" -pytz = "*" +django = ">=4.2" [[package]] name = "djangorestframework-xml" version = "2.0.0" description = "XML support for Django REST Framework" -category = "main" optional = false python-versions = ">=3.5" +files = [ + {file = "djangorestframework-xml-2.0.0.tar.gz", hash = "sha256:35f6c811d0ab8c8466b26db234e16a2ed32d76381715257aebf4c7be2c202ca1"}, + {file = "djangorestframework_xml-2.0.0-py2.py3-none-any.whl", hash = "sha256:975955fbb0d49ac44a90bdeb33b7923d95b79884d283f983e116c80a936ef4d0"}, +] [package.dependencies] defusedxml = ">=0.6.0" [package.extras] -dev = ["mkdocs (>=0.11.1)", "Django (>=1.6)", "djangorestframework (>=2.4.3)", "pytest-django", "pytest", "flake8", "tox", "pre-commit"] +dev = ["Django (>=1.6)", "djangorestframework (>=2.4.3)", "flake8", "mkdocs (>=0.11.1)", "pre-commit", "pytest", "pytest-django", "tox"] docs = ["mkdocs (>=0.11.1)"] -tests = ["Django (>=1.6)", "djangorestframework (>=2.4.3)", "pytest-django", "pytest", "flake8"] +tests = ["Django (>=1.6)", "djangorestframework (>=2.4.3)", "flake8", "pytest", "pytest-django"] [[package]] name = "drf-yasg" -version = "1.20.0" +version = "1.21.11" description = "Automated generation of real Swagger/OpenAPI 2.0 schemas from Django Rest Framework code." -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" +files = [ + {file = "drf_yasg-1.21.11-py3-none-any.whl", hash = "sha256:ec741f313b3b5f0b5fc8c1e1b6ed323c34f1f492a41fe7cc7421d8c6de9753e4"}, + {file = "drf_yasg-1.21.11.tar.gz", hash = "sha256:0190b3de884aa593a39c75e6daba2ae69f285f0691de1eb0e3f4c6307faa1817"}, +] [package.dependencies] -coreapi = ">=2.3.3" -coreschema = ">=0.0.4" -Django = ">=2.2.16" -djangorestframework = ">=3.10.3" +django = ">=4.0" +djangorestframework = ">=3.13" inflection = ">=0.3.1" -packaging = "*" -"ruamel.yaml" = ">=0.15.34" +packaging = ">=21.0" +pytz = ">=2021.1" +pyyaml = ">=5.1" uritemplate = ">=3.0.0" [package.extras] +coreapi = ["coreapi (>=2.3.3)", "coreschema (>=0.0.4)"] validation = ["swagger-spec-validator (>=2.1.0)"] [[package]] name = "environs" -version = "9.5.0" +version = "14.5.0" description = "simplified environment variable parsing" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.10" +files = [ + {file = "environs-14.5.0-py3-none-any.whl", hash = "sha256:1abd3e3a5721fb09797438d6c902bc2f35d4580dfaffe68b8ee588b67b504e13"}, + {file = "environs-14.5.0.tar.gz", hash = "sha256:f7b8f6fcf3301bc674bc9c03e39b5986d116126ffb96764efd34c339ed9464ee"}, +] [package.dependencies] -marshmallow = ">=3.0.0" +marshmallow = ">=3.18.0" python-dotenv = "*" +typing-extensions = {version = "*", markers = "python_version < \"3.11\""} [package.extras] -dev = ["pytest", "dj-database-url", "dj-email-url", "django-cache-url", "flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)", "tox"] +dev = ["environs[tests]", "pre-commit (>=4.0,<5.0)", "tox"] django = ["dj-database-url", "dj-email-url", "django-cache-url"] -lint = ["flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)"] -tests = ["pytest", "dj-database-url", "dj-email-url", "django-cache-url"] +tests = ["backports.strenum", "environs[django]", "packaging", "pytest"] [[package]] name = "et-xmlfile" -version = "1.1.0" +version = "2.0.0" description = "An implementation of lxml.xmlfile for the standard library" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" +files = [ + {file = "et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa"}, + {file = "et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598"}, + {file = "exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] [[package]] name = "filetype" -version = "1.0.10" +version = "1.2.0" description = "Infer file type and MIME type of any file/buffer. No external dependencies." -category = "main" optional = false python-versions = "*" +files = [ + {file = "filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25"}, + {file = "filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb"}, +] [[package]] name = "flake8" version = "4.0.1" description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, + {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, +] [package.dependencies] mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.8.0,<2.9.0" pyflakes = ">=2.4.0,<2.5.0" +[[package]] +name = "flower" +version = "1.2.0" +description = "Celery Flower" +optional = false +python-versions = "*" +files = [ + {file = "flower-1.2.0-py2.py3-none-any.whl", hash = "sha256:ae2977cf7343c526cf44def8c7e7173db8dedb8249b91ba4b88cfd18e7a2d486"}, + {file = "flower-1.2.0.tar.gz", hash = "sha256:46493c7e8d9ca2167e8a46eb97ae8d280997cb40a81993230124d74f0fe40bac"}, +] + +[package.dependencies] +celery = ">=5.0.5" +humanize = "*" +prometheus-client = ">=0.8.0" +pytz = "*" +tornado = ">=5.0.0,<7.0.0" + [[package]] name = "furl" -version = "2.1.3" +version = "2.1.4" description = "URL manipulation made simple." -category = "main" optional = false python-versions = "*" +files = [ + {file = "furl-2.1.4-py2.py3-none-any.whl", hash = "sha256:da34d0b34e53ffe2d2e6851a7085a05d96922b5b578620a37377ff1dbeeb11c8"}, + {file = "furl-2.1.4.tar.gz", hash = "sha256:877657501266c929269739fb5f5980534a41abd6bbabcb367c136d1d3b2a6015"}, +] [package.dependencies] orderedmultidict = ">=1.0.1" @@ -570,183 +1128,321 @@ six = ">=1.8.0" [[package]] name = "google-api-core" -version = "2.7.1" +version = "2.29.0" description = "Google API client core library" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" +files = [ + {file = "google_api_core-2.29.0-py3-none-any.whl", hash = "sha256:d30bc60980daa36e314b5d5a3e5958b0200cb44ca8fa1be2b614e932b75a3ea9"}, + {file = "google_api_core-2.29.0.tar.gz", hash = "sha256:84181be0f8e6b04006df75ddfe728f24489f0af57c96a529ff7cf45bc28797f7"}, +] [package.dependencies] -google-auth = ">=1.25.0,<3.0dev" -googleapis-common-protos = ">=1.52.0,<2.0dev" -protobuf = ">=3.12.0" -requests = ">=2.18.0,<3.0.0dev" +google-auth = ">=2.14.1,<3.0.0" +googleapis-common-protos = ">=1.56.2,<2.0.0" +proto-plus = [ + {version = ">=1.22.3,<2.0.0", markers = "python_version < \"3.13\""}, + {version = ">=1.25.0,<2.0.0", markers = "python_version >= \"3.13\""}, +] +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0" +requests = ">=2.18.0,<3.0.0" [package.extras] -grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio-status (>=1.33.2,<2.0dev)"] -grpcgcp = ["grpcio-gcp (>=0.2.2)"] -grpcio-gcp = ["grpcio-gcp (>=0.2.2)"] +async-rest = ["google-auth[aiohttp] (>=2.35.0,<3.0.0)"] +grpc = ["grpcio (>=1.33.2,<2.0.0)", "grpcio (>=1.49.1,<2.0.0)", "grpcio (>=1.75.1,<2.0.0)", "grpcio-status (>=1.33.2,<2.0.0)", "grpcio-status (>=1.49.1,<2.0.0)", "grpcio-status (>=1.75.1,<2.0.0)"] +grpcgcp = ["grpcio-gcp (>=0.2.2,<1.0.0)"] +grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.0)"] [[package]] name = "google-auth" -version = "2.6.2" +version = "2.47.0" description = "Google Authentication Library" -category = "main" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*" +python-versions = ">=3.8" +files = [ + {file = "google_auth-2.47.0-py3-none-any.whl", hash = "sha256:c516d68336bfde7cf0da26aab674a36fedcf04b37ac4edd59c597178760c3498"}, + {file = "google_auth-2.47.0.tar.gz", hash = "sha256:833229070a9dfee1a353ae9877dcd2dec069a8281a4e72e72f77d4a70ff945da"}, +] [package.dependencies] -cachetools = ">=2.0.0,<6.0" pyasn1-modules = ">=0.2.1" -rsa = {version = ">=3.1.4,<5", markers = "python_version >= \"3.6\""} -six = ">=1.9.0" +rsa = ">=3.1.4,<5" [package.extras] -aiohttp = ["requests (>=2.20.0,<3.0.0dev)", "aiohttp (>=3.6.2,<4.0.0dev)"] -pyopenssl = ["pyopenssl (>=20.0.0)"] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0)", "requests (>=2.20.0,<3.0.0)"] +cryptography = ["cryptography (>=38.0.3)"] +enterprise-cert = ["cryptography", "pyopenssl"] +pyjwt = ["cryptography (>=38.0.3)", "pyjwt (>=2.0)"] +pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] +requests = ["requests (>=2.20.0,<3.0.0)"] +testing = ["aiohttp (<3.10.0)", "aiohttp (>=3.6.2,<4.0.0)", "aioresponses", "cryptography (>=38.0.3)", "cryptography (>=38.0.3)", "flask", "freezegun", "grpcio", "oauth2client", "packaging", "pyjwt (>=2.0)", "pyopenssl (<24.3.0)", "pyopenssl (>=20.0.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-localserver", "pyu2f (>=0.1.5)", "requests (>=2.20.0,<3.0.0)", "responses", "urllib3"] +urllib3 = ["packaging", "urllib3"] [[package]] name = "google-cloud-core" -version = "2.2.3" +version = "2.5.0" description = "Google Cloud API client core library" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" +files = [ + {file = "google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc"}, + {file = "google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963"}, +] [package.dependencies] -google-api-core = ">=1.31.5,<2.0.0 || >2.3.0,<3.0.0dev" -google-auth = ">=1.25.0,<3.0dev" +google-api-core = ">=1.31.6,<2.0.dev0 || >2.3.0,<3.0.0" +google-auth = ">=1.25.0,<3.0.0" [package.extras] -grpc = ["grpcio (>=1.8.2,<2.0dev)"] +grpc = ["grpcio (>=1.38.0,<2.0.0)", "grpcio (>=1.75.1,<2.0.0)", "grpcio-status (>=1.38.0,<2.0.0)"] [[package]] name = "google-cloud-storage" -version = "2.2.1" +version = "3.7.0" description = "Google Cloud Storage API client library" -category = "main" optional = false python-versions = ">=3.7" +files = [ + {file = "google_cloud_storage-3.7.0-py3-none-any.whl", hash = "sha256:469bc9540936e02f8a4bfd1619e9dca1e42dec48f95e4204d783b36476a15093"}, + {file = "google_cloud_storage-3.7.0.tar.gz", hash = "sha256:9ce59c65f4d6e372effcecc0456680a8d73cef4f2dc9212a0704799cb3d69237"}, +] [package.dependencies] -google-api-core = ">=1.31.5,<2.0.0 || >2.3.0,<3.0.0dev" -google-auth = ">=1.25.0,<3.0dev" -google-cloud-core = ">=1.6.0,<3.0dev" -google-resumable-media = ">=2.3.2" -protobuf = "*" -requests = ">=2.18.0,<3.0.0dev" +google-api-core = ">=2.27.0,<3.0.0" +google-auth = ">=2.26.1,<3.0.0" +google-cloud-core = ">=2.4.2,<3.0.0" +google-crc32c = ">=1.1.3,<2.0.0" +google-resumable-media = ">=2.7.2,<3.0.0" +requests = ">=2.22.0,<3.0.0" + +[package.extras] +grpc = ["google-api-core[grpc] (>=2.27.0,<3.0.0)", "grpc-google-iam-v1 (>=0.14.0,<1.0.0)", "grpcio (>=1.33.2,<2.0.0)", "grpcio (>=1.75.1,<2.0.0)", "grpcio-status (>=1.76.0,<2.0.0)", "proto-plus (>=1.22.3,<2.0.0)", "proto-plus (>=1.25.0,<2.0.0)", "protobuf (>=3.20.2,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<7.0.0)"] +protobuf = ["protobuf (>=3.20.2,<7.0.0)"] +tracing = ["opentelemetry-api (>=1.1.0,<2.0.0)"] [[package]] name = "google-crc32c" -version = "1.3.0" +version = "1.8.0" description = "A python wrapper of the C library 'Google CRC32C'" -category = "main" optional = false -python-versions = ">=3.6" - -[package.extras] -testing = ["pytest"] +python-versions = ">=3.9" +files = [ + {file = "google_crc32c-1.8.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0470b8c3d73b5f4e3300165498e4cf25221c7eb37f1159e221d1825b6df8a7ff"}, + {file = "google_crc32c-1.8.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:119fcd90c57c89f30040b47c211acee231b25a45d225e3225294386f5d258288"}, + {file = "google_crc32c-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f35aaffc8ccd81ba3162443fabb920e65b1f20ab1952a31b13173a67811467d"}, + {file = "google_crc32c-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:864abafe7d6e2c4c66395c1eb0fe12dc891879769b52a3d56499612ca93b6092"}, + {file = "google_crc32c-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:db3fe8eaf0612fc8b20fa21a5f25bd785bc3cd5be69f8f3412b0ac2ffd49e733"}, + {file = "google_crc32c-1.8.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:014a7e68d623e9a4222d663931febc3033c5c7c9730785727de2a81f87d5bab8"}, + {file = "google_crc32c-1.8.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:86cfc00fe45a0ac7359e5214a1704e51a99e757d0272554874f419f79838c5f7"}, + {file = "google_crc32c-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:19b40d637a54cb71e0829179f6cb41835f0fbd9e8eb60552152a8b52c36cbe15"}, + {file = "google_crc32c-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:17446feb05abddc187e5441a45971b8394ea4c1b6efd88ab0af393fd9e0a156a"}, + {file = "google_crc32c-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:71734788a88f551fbd6a97be9668a0020698e07b2bf5b3aa26a36c10cdfb27b2"}, + {file = "google_crc32c-1.8.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:4b8286b659c1335172e39563ab0a768b8015e88e08329fa5321f774275fc3113"}, + {file = "google_crc32c-1.8.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:2a3dc3318507de089c5384cc74d54318401410f82aa65b2d9cdde9d297aca7cb"}, + {file = "google_crc32c-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:14f87e04d613dfa218d6135e81b78272c3b904e2a7053b841481b38a7d901411"}, + {file = "google_crc32c-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb5c869c2923d56cb0c8e6bcdd73c009c36ae39b652dbe46a05eb4ef0ad01454"}, + {file = "google_crc32c-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:3cc0c8912038065eafa603b238abf252e204accab2a704c63b9e14837a854962"}, + {file = "google_crc32c-1.8.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:3ebb04528e83b2634857f43f9bb8ef5b2bbe7f10f140daeb01b58f972d04736b"}, + {file = "google_crc32c-1.8.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:450dc98429d3e33ed2926fc99ee81001928d63460f8538f21a5d6060912a8e27"}, + {file = "google_crc32c-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3b9776774b24ba76831609ffbabce8cdf6fa2bd5e9df37b594221c7e333a81fa"}, + {file = "google_crc32c-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89c17d53d75562edfff86679244830599ee0a48efc216200691de8b02ab6b2b8"}, + {file = "google_crc32c-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:57a50a9035b75643996fbf224d6661e386c7162d1dfdab9bc4ca790947d1007f"}, + {file = "google_crc32c-1.8.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:e6584b12cb06796d285d09e33f63309a09368b9d806a551d8036a4207ea43697"}, + {file = "google_crc32c-1.8.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:f4b51844ef67d6cf2e9425983274da75f18b1597bb2c998e1c0a0e8d46f8f651"}, + {file = "google_crc32c-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b0d1a7afc6e8e4635564ba8aa5c0548e3173e41b6384d7711a9123165f582de2"}, + {file = "google_crc32c-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b3f68782f3cbd1bce027e48768293072813469af6a61a86f6bb4977a4380f21"}, + {file = "google_crc32c-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:d511b3153e7011a27ab6ee6bb3a5404a55b994dc1a7322c0b87b29606d9790e2"}, + {file = "google_crc32c-1.8.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:ba6aba18daf4d36ad4412feede6221414692f44d17e5428bdd81ad3fc1eee5dc"}, + {file = "google_crc32c-1.8.0-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:87b0072c4ecc9505cfa16ee734b00cd7721d20a0f595be4d40d3d21b41f65ae2"}, + {file = "google_crc32c-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3d488e98b18809f5e322978d4506373599c0c13e6c5ad13e53bb44758e18d215"}, + {file = "google_crc32c-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01f126a5cfddc378290de52095e2c7052be2ba7656a9f0caf4bcd1bfb1833f8a"}, + {file = "google_crc32c-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:61f58b28e0b21fcb249a8247ad0db2e64114e201e2e9b4200af020f3b6242c9f"}, + {file = "google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:87fa445064e7db928226b2e6f0d5304ab4cd0339e664a4e9a25029f384d9bb93"}, + {file = "google_crc32c-1.8.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f639065ea2042d5c034bf258a9f085eaa7af0cd250667c0635a3118e8f92c69c"}, + {file = "google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79"}, +] [[package]] name = "google-resumable-media" -version = "2.3.2" +version = "2.8.0" description = "Utilities for Google Media Downloads and Resumable Uploads" -category = "main" optional = false -python-versions = ">= 3.6" +python-versions = ">=3.7" +files = [ + {file = "google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582"}, + {file = "google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae"}, +] [package.dependencies] -google-crc32c = ">=1.0,<2.0dev" +google-crc32c = ">=1.0.0,<2.0.0" [package.extras] -aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)"] -requests = ["requests (>=2.18.0,<3.0.0dev)"] +aiohttp = ["aiohttp (>=3.6.2,<4.0.0)", "google-auth (>=1.22.0,<2.0.0)"] +requests = ["requests (>=2.18.0,<3.0.0)"] [[package]] name = "googleapis-common-protos" -version = "1.56.0" +version = "1.72.0" description = "Common protobufs used in Google APIs" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" +files = [ + {file = "googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038"}, + {file = "googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5"}, +] [package.dependencies] -protobuf = ">=3.12.0" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0" [package.extras] -grpc = ["grpcio (>=1.0.0)"] +grpc = ["grpcio (>=1.44.0,<2.0.0)"] [[package]] name = "greenlet" -version = "1.1.2" +version = "3.3.0" description = "Lightweight in-process concurrent programming" -category = "main" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +python-versions = ">=3.10" +files = [ + {file = "greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d"}, + {file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb"}, + {file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73631cd5cccbcfe63e3f9492aaa664d278fda0ce5c3d43aeda8e77317e38efbd"}, + {file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b299a0cb979f5d7197442dccc3aee67fce53500cd88951b7e6c35575701c980b"}, + {file = "greenlet-3.3.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7dee147740789a4632cace364816046e43310b59ff8fb79833ab043aefa72fd5"}, + {file = "greenlet-3.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39b28e339fc3c348427560494e28d8a6f3561c8d2bcf7d706e1c624ed8d822b9"}, + {file = "greenlet-3.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3c374782c2935cc63b2a27ba8708471de4ad1abaa862ffdb1ef45a643ddbb7d"}, + {file = "greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082"}, + {file = "greenlet-3.3.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e29f3018580e8412d6aaf5641bb7745d38c85228dacf51a73bd4e26ddf2a6a8e"}, + {file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a687205fb22794e838f947e2194c0566d3812966b41c78709554aa883183fb62"}, + {file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4243050a88ba61842186cb9e63c7dfa677ec146160b0efd73b855a3d9c7fcf32"}, + {file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:670d0f94cd302d81796e37299bcd04b95d62403883b24225c6b5271466612f45"}, + {file = "greenlet-3.3.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cb3a8ec3db4a3b0eb8a3c25436c2d49e3505821802074969db017b87bc6a948"}, + {file = "greenlet-3.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2de5a0b09eab81fc6a382791b995b1ccf2b172a9fec934747a7a23d2ff291794"}, + {file = "greenlet-3.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4449a736606bd30f27f8e1ff4678ee193bc47f6ca810d705981cfffd6ce0d8c5"}, + {file = "greenlet-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:7652ee180d16d447a683c04e4c5f6441bae7ba7b17ffd9f6b3aff4605e9e6f71"}, + {file = "greenlet-3.3.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:b01548f6e0b9e9784a2c99c5651e5dc89ffcbe870bc5fb2e5ef864e9cc6b5dcb"}, + {file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:349345b770dc88f81506c6861d22a6ccd422207829d2c854ae2af8025af303e3"}, + {file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e8e18ed6995e9e2c0b4ed264d2cf89260ab3ac7e13555b8032b25a74c6d18655"}, + {file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c024b1e5696626890038e34f76140ed1daf858e37496d33f2af57f06189e70d7"}, + {file = "greenlet-3.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:047ab3df20ede6a57c35c14bf5200fcf04039d50f908270d3f9a7a82064f543b"}, + {file = "greenlet-3.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d9ad37fc657b1102ec880e637cccf20191581f75c64087a549e66c57e1ceb53"}, + {file = "greenlet-3.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83cd0e36932e0e7f36a64b732a6f60c2fc2df28c351bae79fbaf4f8092fe7614"}, + {file = "greenlet-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7a34b13d43a6b78abf828a6d0e87d3385680eaf830cd60d20d52f249faabf39"}, + {file = "greenlet-3.3.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:a1e41a81c7e2825822f4e068c48cb2196002362619e2d70b148f20a831c00739"}, + {file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f515a47d02da4d30caaa85b69474cec77b7929b2e936ff7fb853d42f4bf8808"}, + {file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7d2d9fd66bfadf230b385fdc90426fcd6eb64db54b40c495b72ac0feb5766c54"}, + {file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30a6e28487a790417d036088b3bcb3f3ac7d8babaa7d0139edbaddebf3af9492"}, + {file = "greenlet-3.3.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:087ea5e004437321508a8d6f20efc4cfec5e3c30118e1417ea96ed1d93950527"}, + {file = "greenlet-3.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ab97cf74045343f6c60a39913fa59710e4bd26a536ce7ab2397adf8b27e67c39"}, + {file = "greenlet-3.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5375d2e23184629112ca1ea89a53389dddbffcf417dad40125713d88eb5f96e8"}, + {file = "greenlet-3.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:9ee1942ea19550094033c35d25d20726e4f1c40d59545815e1128ac58d416d38"}, + {file = "greenlet-3.3.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:60c2ef0f578afb3c8d92ea07ad327f9a062547137afe91f38408f08aacab667f"}, + {file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a5d554d0712ba1de0a6c94c640f7aeba3f85b3a6e1f2899c11c2c0428da9365"}, + {file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3a898b1e9c5f7307ebbde4102908e6cbfcb9ea16284a3abe15cab996bee8b9b3"}, + {file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:dcd2bdbd444ff340e8d6bdf54d2f206ccddbb3ccfdcd3c25bf4afaa7b8f0cf45"}, + {file = "greenlet-3.3.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5773edda4dc00e173820722711d043799d3adb4f01731f40619e07ea2750b955"}, + {file = "greenlet-3.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ac0549373982b36d5fd5d30beb8a7a33ee541ff98d2b502714a09f1169f31b55"}, + {file = "greenlet-3.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d198d2d977460358c3b3a4dc844f875d1adb33817f0613f663a656f463764ccc"}, + {file = "greenlet-3.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:73f51dd0e0bdb596fb0417e475fa3c5e32d4c83638296e560086b8d7da7c4170"}, + {file = "greenlet-3.3.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d6ed6f85fae6cdfdb9ce04c9bf7a08d666cfcfb914e7d006f44f840b46741931"}, + {file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9125050fcf24554e69c4cacb086b87b3b55dc395a8b3ebe6487b045b2614388"}, + {file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:87e63ccfa13c0a0f6234ed0add552af24cc67dd886731f2261e46e241608bee3"}, + {file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2662433acbca297c9153a4023fe2161c8dcfdcc91f10433171cf7e7d94ba2221"}, + {file = "greenlet-3.3.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3c6e9b9c1527a78520357de498b0e709fb9e2f49c3a513afd5a249007261911b"}, + {file = "greenlet-3.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:286d093f95ec98fdd92fcb955003b8a3d054b4e2cab3e2707a5039e7b50520fd"}, + {file = "greenlet-3.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c10513330af5b8ae16f023e8ddbfb486ab355d04467c4679c5cfe4659975dd9"}, + {file = "greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb"}, +] [package.extras] -docs = ["sphinx"] +docs = ["Sphinx", "furo"] +test = ["objgraph", "psutil", "setuptools"] [[package]] name = "gunicorn" -version = "20.1.0" +version = "23.0.0" description = "WSGI HTTP Server for UNIX" -category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" +files = [ + {file = "gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"}, + {file = "gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"}, +] + +[package.dependencies] +packaging = "*" [package.extras] -eventlet = ["eventlet (>=0.24.1)"] +eventlet = ["eventlet (>=0.24.1,!=0.36.0)"] gevent = ["gevent (>=1.4.0)"] setproctitle = ["setproctitle"] +testing = ["coverage", "eventlet", "gevent", "pytest", "pytest-cov"] tornado = ["tornado (>=0.2)"] +[[package]] +name = "humanize" +version = "4.15.0" +description = "Python humanize utilities" +optional = false +python-versions = ">=3.10" +files = [ + {file = "humanize-4.15.0-py3-none-any.whl", hash = "sha256:b1186eb9f5a9749cd9cb8565aee77919dd7c8d076161cf44d70e59e3301e1769"}, + {file = "humanize-4.15.0.tar.gz", hash = "sha256:1dd098483eb1c7ee8e32eb2e99ad1910baefa4b75c3aff3a82f4d78688993b10"}, +] + +[package.extras] +tests = ["freezegun", "pytest", "pytest-cov"] + [[package]] name = "idna" -version = "3.3" +version = "3.11" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" +files = [ + {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, + {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] [[package]] name = "inflection" version = "0.5.1" description = "A port of Ruby on Rails inflector to Python" -category = "main" optional = false python-versions = ">=3.5" +files = [ + {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, + {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, +] [[package]] name = "isort" -version = "5.10.1" +version = "5.13.2" description = "A Python utility / library to sort Python imports." -category = "dev" optional = false -python-versions = ">=3.6.1,<4.0" +python-versions = ">=3.8.0" +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] [package.extras] -pipfile_deprecated_finder = ["pipreqs", "requirementslib"] -requirements_deprecated_finder = ["pipreqs", "pip-api"] -colors = ["colorama (>=0.4.3,<0.5.0)"] -plugins = ["setuptools"] - -[[package]] -name = "itypes" -version = "1.2.0" -description = "Simple immutable types for python." -category = "main" -optional = false -python-versions = "*" +colors = ["colorama (>=0.4.6)"] [[package]] name = "jinja2" -version = "3.0.3" +version = "3.1.6" description = "A very fast and expressive template engine." -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, +] [package.dependencies] MarkupSafe = ">=2.0" @@ -756,309 +1452,1178 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jmespath" -version = "0.10.0" +version = "1.0.1" description = "JSON Matching Expressions" -category = "main" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = ">=3.7" +files = [ + {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, + {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, +] [[package]] name = "joblib" -version = "1.1.0" +version = "1.5.3" description = "Lightweight pipelining with Python functions" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" +files = [ + {file = "joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713"}, + {file = "joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3"}, +] [[package]] name = "kombu" -version = "5.2.3" +version = "5.6.2" description = "Messaging library for Python." -category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +files = [ + {file = "kombu-5.6.2-py3-none-any.whl", hash = "sha256:efcfc559da324d41d61ca311b0c64965ea35b4c55cc04ee36e55386145dace93"}, + {file = "kombu-5.6.2.tar.gz", hash = "sha256:8060497058066c6f5aed7c26d7cd0d3b574990b09de842a8c5aaed0b92cc5a55"}, +] [package.dependencies] -amqp = ">=5.0.9,<6.0.0" -vine = "*" +amqp = ">=5.1.1,<6.0.0" +packaging = "*" +tzdata = ">=2025.2" +vine = "5.1.0" [package.extras] -azureservicebus = ["azure-servicebus (>=7.0.0)"] -azurestoragequeues = ["azure-storage-queue"] -consul = ["python-consul (>=0.6.0)"] +azureservicebus = ["azure-servicebus (>=7.10.0)"] +azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] +confluentkafka = ["confluent-kafka (>=2.2.0)"] +consul = ["python-consul2 (==0.1.5)"] +gcpubsub = ["google-cloud-monitoring (>=2.16.0)", "google-cloud-pubsub (>=2.18.4)", "grpcio (==1.75.1)", "protobuf (==6.32.1)"] librabbitmq = ["librabbitmq (>=2.0.0)"] -mongodb = ["pymongo (>=3.3.0,<3.12.1)"] -msgpack = ["msgpack"] -pyro = ["pyro4"] -qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"] -redis = ["redis (>=3.4.1,!=4.0.0,!=4.0.1)"] -slmq = ["softlayer-messaging (>=1.0.3)"] -sqlalchemy = ["sqlalchemy"] -sqs = ["boto3 (>=1.9.12)", "pycurl (>=7.44.1,<7.45.0)", "urllib3 (>=1.26.7)"] +mongodb = ["pymongo (==4.15.3)"] +msgpack = ["msgpack (==1.1.2)"] +pyro = ["pyro4 (==4.82)"] +qpid = ["qpid-python (==1.36.0-1)", "qpid-tools (==1.36.0-1)"] +redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2,<6.5)"] +slmq = ["softlayer_messaging (>=1.0.3)"] +sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] +sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] yaml = ["PyYAML (>=3.10)"] -zookeeper = ["kazoo (>=1.3.1)"] +zookeeper = ["kazoo (>=2.8.0)"] + +[[package]] +name = "librt" +version = "0.7.7" +description = "Mypyc runtime library" +optional = false +python-versions = ">=3.9" +files = [ + {file = "librt-0.7.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4836c5645f40fbdc275e5670819bde5ab5f2e882290d304e3c6ddab1576a6d0"}, + {file = "librt-0.7.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae8aec43117a645a31e5f60e9e3a0797492e747823b9bda6972d521b436b4e8"}, + {file = "librt-0.7.7-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:aea05f701ccd2a76b34f0daf47ca5068176ff553510b614770c90d76ac88df06"}, + {file = "librt-0.7.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7b16ccaeff0ed4355dfb76fe1ea7a5d6d03b5ad27f295f77ee0557bc20a72495"}, + {file = "librt-0.7.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c48c7e150c095d5e3cea7452347ba26094be905d6099d24f9319a8b475fcd3e0"}, + {file = "librt-0.7.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4dcee2f921a8632636d1c37f1bbdb8841d15666d119aa61e5399c5268e7ce02e"}, + {file = "librt-0.7.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:14ef0f4ac3728ffd85bfc58e2f2f48fb4ef4fa871876f13a73a7381d10a9f77c"}, + {file = "librt-0.7.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e4ab69fa37f8090f2d971a5d2bc606c7401170dbdae083c393d6cbf439cb45b8"}, + {file = "librt-0.7.7-cp310-cp310-win32.whl", hash = "sha256:4bf3cc46d553693382d2abf5f5bd493d71bb0f50a7c0beab18aa13a5545c8900"}, + {file = "librt-0.7.7-cp310-cp310-win_amd64.whl", hash = "sha256:f0c8fe5aeadd8a0e5b0598f8a6ee3533135ca50fd3f20f130f9d72baf5c6ac58"}, + {file = "librt-0.7.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a487b71fbf8a9edb72a8c7a456dda0184642d99cd007bc819c0b7ab93676a8ee"}, + {file = "librt-0.7.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f4d4efb218264ecf0f8516196c9e2d1a0679d9fb3bb15df1155a35220062eba8"}, + {file = "librt-0.7.7-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b8bb331aad734b059c4b450cd0a225652f16889e286b2345af5e2c3c625c3d85"}, + {file = "librt-0.7.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:467dbd7443bda08338fc8ad701ed38cef48194017554f4c798b0a237904b3f99"}, + {file = "librt-0.7.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50d1d1ee813d2d1a3baf2873634ba506b263032418d16287c92ec1cc9c1a00cb"}, + {file = "librt-0.7.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c7e5070cf3ec92d98f57574da0224f8c73faf1ddd6d8afa0b8c9f6e86997bc74"}, + {file = "librt-0.7.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:bdb9f3d865b2dafe7f9ad7f30ef563c80d0ddd2fdc8cc9b8e4f242f475e34d75"}, + {file = "librt-0.7.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8185c8497d45164e256376f9da5aed2bb26ff636c798c9dabe313b90e9f25b28"}, + {file = "librt-0.7.7-cp311-cp311-win32.whl", hash = "sha256:44d63ce643f34a903f09ff7ca355aae019a3730c7afd6a3c037d569beeb5d151"}, + {file = "librt-0.7.7-cp311-cp311-win_amd64.whl", hash = "sha256:7d13cc340b3b82134f8038a2bfe7137093693dcad8ba5773da18f95ad6b77a8a"}, + {file = "librt-0.7.7-cp311-cp311-win_arm64.whl", hash = "sha256:983de36b5a83fe9222f4f7dcd071f9b1ac6f3f17c0af0238dadfb8229588f890"}, + {file = "librt-0.7.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2a85a1fc4ed11ea0eb0a632459ce004a2d14afc085a50ae3463cd3dfe1ce43fc"}, + {file = "librt-0.7.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c87654e29a35938baead1c4559858f346f4a2a7588574a14d784f300ffba0efd"}, + {file = "librt-0.7.7-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c9faaebb1c6212c20afd8043cd6ed9de0a47d77f91a6b5b48f4e46ed470703fe"}, + {file = "librt-0.7.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1908c3e5a5ef86b23391448b47759298f87f997c3bd153a770828f58c2bb4630"}, + {file = "librt-0.7.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dbc4900e95a98fc0729523be9d93a8fedebb026f32ed9ffc08acd82e3e181503"}, + {file = "librt-0.7.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a7ea4e1fbd253e5c68ea0fe63d08577f9d288a73f17d82f652ebc61fa48d878d"}, + {file = "librt-0.7.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ef7699b7a5a244b1119f85c5bbc13f152cd38240cbb2baa19b769433bae98e50"}, + {file = "librt-0.7.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:955c62571de0b181d9e9e0a0303c8bc90d47670a5eff54cf71bf5da61d1899cf"}, + {file = "librt-0.7.7-cp312-cp312-win32.whl", hash = "sha256:1bcd79be209313b270b0e1a51c67ae1af28adad0e0c7e84c3ad4b5cb57aaa75b"}, + {file = "librt-0.7.7-cp312-cp312-win_amd64.whl", hash = "sha256:4353ee891a1834567e0302d4bd5e60f531912179578c36f3d0430f8c5e16b456"}, + {file = "librt-0.7.7-cp312-cp312-win_arm64.whl", hash = "sha256:a76f1d679beccccdf8c1958e732a1dfcd6e749f8821ee59d7bec009ac308c029"}, + {file = "librt-0.7.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f4a0b0a3c86ba9193a8e23bb18f100d647bf192390ae195d84dfa0a10fb6244"}, + {file = "librt-0.7.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5335890fea9f9e6c4fdf8683061b9ccdcbe47c6dc03ab8e9b68c10acf78be78d"}, + {file = "librt-0.7.7-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9b4346b1225be26def3ccc6c965751c74868f0578cbcba293c8ae9168483d811"}, + {file = "librt-0.7.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a10b8eebdaca6e9fdbaf88b5aefc0e324b763a5f40b1266532590d5afb268a4c"}, + {file = "librt-0.7.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:067be973d90d9e319e6eb4ee2a9b9307f0ecd648b8a9002fa237289a4a07a9e7"}, + {file = "librt-0.7.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:23d2299ed007812cccc1ecef018db7d922733382561230de1f3954db28433977"}, + {file = "librt-0.7.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6b6f8ea465524aa4c7420c7cc4ca7d46fe00981de8debc67b1cc2e9957bb5b9d"}, + {file = "librt-0.7.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8df32a99cc46eb0ee90afd9ada113ae2cafe7e8d673686cf03ec53e49635439"}, + {file = "librt-0.7.7-cp313-cp313-win32.whl", hash = "sha256:86f86b3b785487c7760247bcdac0b11aa8bf13245a13ed05206286135877564b"}, + {file = "librt-0.7.7-cp313-cp313-win_amd64.whl", hash = "sha256:4862cb2c702b1f905c0503b72d9d4daf65a7fdf5a9e84560e563471e57a56949"}, + {file = "librt-0.7.7-cp313-cp313-win_arm64.whl", hash = "sha256:0996c83b1cb43c00e8c87835a284f9057bc647abd42b5871e5f941d30010c832"}, + {file = "librt-0.7.7-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:23daa1ab0512bafdd677eb1bfc9611d8ffbe2e328895671e64cb34166bc1b8c8"}, + {file = "librt-0.7.7-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:558a9e5a6f3cc1e20b3168fb1dc802d0d8fa40731f6e9932dcc52bbcfbd37111"}, + {file = "librt-0.7.7-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2567cb48dc03e5b246927ab35cbb343376e24501260a9b5e30b8e255dca0d1d2"}, + {file = "librt-0.7.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6066c638cdf85ff92fc6f932d2d73c93a0e03492cdfa8778e6d58c489a3d7259"}, + {file = "librt-0.7.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a609849aca463074c17de9cda173c276eb8fee9e441053529e7b9e249dc8b8ee"}, + {file = "librt-0.7.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:add4e0a000858fe9bb39ed55f31085506a5c38363e6eb4a1e5943a10c2bfc3d1"}, + {file = "librt-0.7.7-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a3bfe73a32bd0bdb9a87d586b05a23c0a1729205d79df66dee65bb2e40d671ba"}, + {file = "librt-0.7.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0ecce0544d3db91a40f8b57ae26928c02130a997b540f908cefd4d279d6c5848"}, + {file = "librt-0.7.7-cp314-cp314-win32.whl", hash = "sha256:8f7a74cf3a80f0c3b0ec75b0c650b2f0a894a2cec57ef75f6f72c1e82cdac61d"}, + {file = "librt-0.7.7-cp314-cp314-win_amd64.whl", hash = "sha256:3d1fe2e8df3268dd6734dba33ededae72ad5c3a859b9577bc00b715759c5aaab"}, + {file = "librt-0.7.7-cp314-cp314-win_arm64.whl", hash = "sha256:2987cf827011907d3dfd109f1be0d61e173d68b1270107bb0e89f2fca7f2ed6b"}, + {file = "librt-0.7.7-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8e92c8de62b40bfce91d5e12c6e8b15434da268979b1af1a6589463549d491e6"}, + {file = "librt-0.7.7-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f683dcd49e2494a7535e30f779aa1ad6e3732a019d80abe1309ea91ccd3230e3"}, + {file = "librt-0.7.7-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9b15e5d17812d4d629ff576699954f74e2cc24a02a4fc401882dd94f81daba45"}, + {file = "librt-0.7.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c084841b879c4d9b9fa34e5d5263994f21aea7fd9c6add29194dbb41a6210536"}, + {file = "librt-0.7.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10c8fb9966f84737115513fecbaf257f9553d067a7dd45a69c2c7e5339e6a8dc"}, + {file = "librt-0.7.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9b5fb1ecb2c35362eab2dbd354fd1efa5a8440d3e73a68be11921042a0edc0ff"}, + {file = "librt-0.7.7-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:d1454899909d63cc9199a89fcc4f81bdd9004aef577d4ffc022e600c412d57f3"}, + {file = "librt-0.7.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7ef28f2e7a016b29792fe0a2dd04dec75725b32a1264e390c366103f834a9c3a"}, + {file = "librt-0.7.7-cp314-cp314t-win32.whl", hash = "sha256:5e419e0db70991b6ba037b70c1d5bbe92b20ddf82f31ad01d77a347ed9781398"}, + {file = "librt-0.7.7-cp314-cp314t-win_amd64.whl", hash = "sha256:d6b7d93657332c817b8d674ef6bf1ab7796b4f7ce05e420fd45bd258a72ac804"}, + {file = "librt-0.7.7-cp314-cp314t-win_arm64.whl", hash = "sha256:142c2cd91794b79fd0ce113bd658993b7ede0fe93057668c2f98a45ca00b7e91"}, + {file = "librt-0.7.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c8ffe3431d98cc043a14e88b21288b5ec7ee12cb01260e94385887f285ef9389"}, + {file = "librt-0.7.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e40d20ae1722d6b8ea6acf4597e789604649dcd9c295eb7361a28225bc2e9e12"}, + {file = "librt-0.7.7-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f2cb63c49bc96847c3bb8dca350970e4dcd19936f391cfdfd057dcb37c4fa97e"}, + {file = "librt-0.7.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f2f8dcf5ab9f80fb970c6fd780b398efb2f50c1962485eb8d3ab07788595a48"}, + {file = "librt-0.7.7-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a1f5cc41a570269d1be7a676655875e3a53de4992a9fa38efb7983e97cf73d7c"}, + {file = "librt-0.7.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ff1fb2dfef035549565a4124998fadcb7a3d4957131ddf004a56edeb029626b3"}, + {file = "librt-0.7.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ab2a2a9cd7d044e1a11ca64a86ad3361d318176924bbe5152fbc69f99be20b8c"}, + {file = "librt-0.7.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ad3fc2d859a709baf9dd9607bb72f599b1cfb8a39eafd41307d0c3c4766763cb"}, + {file = "librt-0.7.7-cp39-cp39-win32.whl", hash = "sha256:f83c971eb9d2358b6a18da51dc0ae00556ac7c73104dde16e9e14c15aaf685ca"}, + {file = "librt-0.7.7-cp39-cp39-win_amd64.whl", hash = "sha256:264720fc288c86039c091a4ad63419a5d7cabbf1c1c9933336a957ed2483e570"}, + {file = "librt-0.7.7.tar.gz", hash = "sha256:81d957b069fed1890953c3b9c3895c7689960f233eea9a1d9607f71ce7f00b2c"}, +] [[package]] name = "lml" -version = "0.1.0" +version = "0.2.0" description = "Load me later. A lazy plugin management system." -category = "main" optional = false python-versions = "*" +files = [ + {file = "lml-0.2.0-py2.py3-none-any.whl", hash = "sha256:20c80728189e46e8d986f5d0cdf6d83c493471fc25b1c31a8cb3fa96e80b58f8"}, + {file = "lml-0.2.0.tar.gz", hash = "sha256:8dd5afb4367a593d1cdb2144a05874cd9938f5266bebb0c9e1413200423c0d74"}, +] [[package]] name = "lxml" -version = "4.9.1" +version = "6.0.2" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." -category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" +python-versions = ">=3.8" +files = [ + {file = "lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388"}, + {file = "lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153"}, + {file = "lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31"}, + {file = "lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9"}, + {file = "lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8"}, + {file = "lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba"}, + {file = "lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c"}, + {file = "lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c"}, + {file = "lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321"}, + {file = "lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1"}, + {file = "lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34"}, + {file = "lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a"}, + {file = "lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c"}, + {file = "lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b"}, + {file = "lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0"}, + {file = "lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5"}, + {file = "lxml-6.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:13e35cbc684aadf05d8711a5d1b5857c92e5e580efa9a0d2be197199c8def607"}, + {file = "lxml-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b1675e096e17c6fe9c0e8c81434f5736c0739ff9ac6123c87c2d452f48fc938"}, + {file = "lxml-6.0.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac6e5811ae2870953390452e3476694196f98d447573234592d30488147404d"}, + {file = "lxml-6.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5aa0fc67ae19d7a64c3fe725dc9a1bb11f80e01f78289d05c6f62545affec438"}, + {file = "lxml-6.0.2-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de496365750cc472b4e7902a485d3f152ecf57bd3ba03ddd5578ed8ceb4c5964"}, + {file = "lxml-6.0.2-cp311-cp311-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:200069a593c5e40b8f6fc0d84d86d970ba43138c3e68619ffa234bc9bb806a4d"}, + {file = "lxml-6.0.2-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d2de809c2ee3b888b59f995625385f74629707c9355e0ff856445cdcae682b7"}, + {file = "lxml-6.0.2-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:b2c3da8d93cf5db60e8858c17684c47d01fee6405e554fb55018dd85fc23b178"}, + {file = "lxml-6.0.2-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:442de7530296ef5e188373a1ea5789a46ce90c4847e597856570439621d9c553"}, + {file = "lxml-6.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2593c77efde7bfea7f6389f1ab249b15ed4aa5bc5cb5131faa3b843c429fbedb"}, + {file = "lxml-6.0.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:3e3cb08855967a20f553ff32d147e14329b3ae70ced6edc2f282b94afbc74b2a"}, + {file = "lxml-6.0.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2ed6c667fcbb8c19c6791bbf40b7268ef8ddf5a96940ba9404b9f9a304832f6c"}, + {file = "lxml-6.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b8f18914faec94132e5b91e69d76a5c1d7b0c73e2489ea8929c4aaa10b76bbf7"}, + {file = "lxml-6.0.2-cp311-cp311-win32.whl", hash = "sha256:6605c604e6daa9e0d7f0a2137bdc47a2e93b59c60a65466353e37f8272f47c46"}, + {file = "lxml-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e5867f2651016a3afd8dd2c8238baa66f1e2802f44bc17e236f547ace6647078"}, + {file = "lxml-6.0.2-cp311-cp311-win_arm64.whl", hash = "sha256:4197fb2534ee05fd3e7afaab5d8bfd6c2e186f65ea7f9cd6a82809c887bd1285"}, + {file = "lxml-6.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a59f5448ba2ceccd06995c95ea59a7674a10de0810f2ce90c9006f3cbc044456"}, + {file = "lxml-6.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e8113639f3296706fbac34a30813929e29247718e88173ad849f57ca59754924"}, + {file = "lxml-6.0.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a8bef9b9825fa8bc816a6e641bb67219489229ebc648be422af695f6e7a4fa7f"}, + {file = "lxml-6.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:65ea18d710fd14e0186c2f973dc60bb52039a275f82d3c44a0e42b43440ea534"}, + {file = "lxml-6.0.2-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c371aa98126a0d4c739ca93ceffa0fd7a5d732e3ac66a46e74339acd4d334564"}, + {file = "lxml-6.0.2-cp312-cp312-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:700efd30c0fa1a3581d80a748157397559396090a51d306ea59a70020223d16f"}, + {file = "lxml-6.0.2-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c33e66d44fe60e72397b487ee92e01da0d09ba2d66df8eae42d77b6d06e5eba0"}, + {file = "lxml-6.0.2-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90a345bbeaf9d0587a3aaffb7006aa39ccb6ff0e96a57286c0cb2fd1520ea192"}, + {file = "lxml-6.0.2-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:064fdadaf7a21af3ed1dcaa106b854077fbeada827c18f72aec9346847cd65d0"}, + {file = "lxml-6.0.2-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbc74f42c3525ac4ffa4b89cbdd00057b6196bcefe8bce794abd42d33a018092"}, + {file = "lxml-6.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6ddff43f702905a4e32bc24f3f2e2edfe0f8fde3277d481bffb709a4cced7a1f"}, + {file = "lxml-6.0.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6da5185951d72e6f5352166e3da7b0dc27aa70bd1090b0eb3f7f7212b53f1bb8"}, + {file = "lxml-6.0.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:57a86e1ebb4020a38d295c04fc79603c7899e0df71588043eb218722dabc087f"}, + {file = "lxml-6.0.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2047d8234fe735ab77802ce5f2297e410ff40f5238aec569ad7c8e163d7b19a6"}, + {file = "lxml-6.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f91fd2b2ea15a6800c8e24418c0775a1694eefc011392da73bc6cef2623b322"}, + {file = "lxml-6.0.2-cp312-cp312-win32.whl", hash = "sha256:3ae2ce7d6fedfb3414a2b6c5e20b249c4c607f72cb8d2bb7cc9c6ec7c6f4e849"}, + {file = "lxml-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:72c87e5ee4e58a8354fb9c7c84cbf95a1c8236c127a5d1b7683f04bed8361e1f"}, + {file = "lxml-6.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:61cb10eeb95570153e0c0e554f58df92ecf5109f75eacad4a95baa709e26c3d6"}, + {file = "lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77"}, + {file = "lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f"}, + {file = "lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452"}, + {file = "lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048"}, + {file = "lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df"}, + {file = "lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1"}, + {file = "lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916"}, + {file = "lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd"}, + {file = "lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6"}, + {file = "lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a"}, + {file = "lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679"}, + {file = "lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659"}, + {file = "lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484"}, + {file = "lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2"}, + {file = "lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314"}, + {file = "lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2"}, + {file = "lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7"}, + {file = "lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf"}, + {file = "lxml-6.0.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:b0c732aa23de8f8aec23f4b580d1e52905ef468afb4abeafd3fec77042abb6fe"}, + {file = "lxml-6.0.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4468e3b83e10e0317a89a33d28f7aeba1caa4d1a6fd457d115dd4ffe90c5931d"}, + {file = "lxml-6.0.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:abd44571493973bad4598a3be7e1d807ed45aa2adaf7ab92ab7c62609569b17d"}, + {file = "lxml-6.0.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:370cd78d5855cfbffd57c422851f7d3864e6ae72d0da615fca4dad8c45d375a5"}, + {file = "lxml-6.0.2-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:901e3b4219fa04ef766885fb40fa516a71662a4c61b80c94d25336b4934b71c0"}, + {file = "lxml-6.0.2-cp314-cp314-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:a4bf42d2e4cf52c28cc1812d62426b9503cdb0c87a6de81442626aa7d69707ba"}, + {file = "lxml-6.0.2-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2c7fdaa4d7c3d886a42534adec7cfac73860b89b4e5298752f60aa5984641a0"}, + {file = "lxml-6.0.2-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98a5e1660dc7de2200b00d53fa00bcd3c35a3608c305d45a7bbcaf29fa16e83d"}, + {file = "lxml-6.0.2-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:dc051506c30b609238d79eda75ee9cab3e520570ec8219844a72a46020901e37"}, + {file = "lxml-6.0.2-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8799481bbdd212470d17513a54d568f44416db01250f49449647b5ab5b5dccb9"}, + {file = "lxml-6.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9261bb77c2dab42f3ecd9103951aeca2c40277701eb7e912c545c1b16e0e4917"}, + {file = "lxml-6.0.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:65ac4a01aba353cfa6d5725b95d7aed6356ddc0a3cd734de00124d285b04b64f"}, + {file = "lxml-6.0.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:b22a07cbb82fea98f8a2fd814f3d1811ff9ed76d0fc6abc84eb21527596e7cc8"}, + {file = "lxml-6.0.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d759cdd7f3e055d6bc8d9bec3ad905227b2e4c785dc16c372eb5b5e83123f48a"}, + {file = "lxml-6.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:945da35a48d193d27c188037a05fec5492937f66fb1958c24fc761fb9d40d43c"}, + {file = "lxml-6.0.2-cp314-cp314-win32.whl", hash = "sha256:be3aaa60da67e6153eb15715cc2e19091af5dc75faef8b8a585aea372507384b"}, + {file = "lxml-6.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:fa25afbadead523f7001caf0c2382afd272c315a033a7b06336da2637d92d6ed"}, + {file = "lxml-6.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:063eccf89df5b24e361b123e257e437f9e9878f425ee9aae3144c77faf6da6d8"}, + {file = "lxml-6.0.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:6162a86d86893d63084faaf4ff937b3daea233e3682fb4474db07395794fa80d"}, + {file = "lxml-6.0.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:414aaa94e974e23a3e92e7ca5b97d10c0cf37b6481f50911032c69eeb3991bba"}, + {file = "lxml-6.0.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48461bd21625458dd01e14e2c38dd0aea69addc3c4f960c30d9f59d7f93be601"}, + {file = "lxml-6.0.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:25fcc59afc57d527cfc78a58f40ab4c9b8fd096a9a3f964d2781ffb6eb33f4ed"}, + {file = "lxml-6.0.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5179c60288204e6ddde3f774a93350177e08876eaf3ab78aa3a3649d43eb7d37"}, + {file = "lxml-6.0.2-cp314-cp314t-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:967aab75434de148ec80597b75062d8123cadf2943fb4281f385141e18b21338"}, + {file = "lxml-6.0.2-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d100fcc8930d697c6561156c6810ab4a508fb264c8b6779e6e61e2ed5e7558f9"}, + {file = "lxml-6.0.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ca59e7e13e5981175b8b3e4ab84d7da57993eeff53c07764dcebda0d0e64ecd"}, + {file = "lxml-6.0.2-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:957448ac63a42e2e49531b9d6c0fa449a1970dbc32467aaad46f11545be9af1d"}, + {file = "lxml-6.0.2-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7fc49c37f1786284b12af63152fe1d0990722497e2d5817acfe7a877522f9a9"}, + {file = "lxml-6.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e19e0643cc936a22e837f79d01a550678da8377d7d801a14487c10c34ee49c7e"}, + {file = "lxml-6.0.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:1db01e5cf14345628e0cbe71067204db658e2fb8e51e7f33631f5f4735fefd8d"}, + {file = "lxml-6.0.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:875c6b5ab39ad5291588aed6925fac99d0097af0dd62f33c7b43736043d4a2ec"}, + {file = "lxml-6.0.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:cdcbed9ad19da81c480dfd6dd161886db6096083c9938ead313d94b30aadf272"}, + {file = "lxml-6.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80dadc234ebc532e09be1975ff538d154a7fa61ea5031c03d25178855544728f"}, + {file = "lxml-6.0.2-cp314-cp314t-win32.whl", hash = "sha256:da08e7bb297b04e893d91087df19638dc7a6bb858a954b0cc2b9f5053c922312"}, + {file = "lxml-6.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:252a22982dca42f6155125ac76d3432e548a7625d56f5a273ee78a5057216eca"}, + {file = "lxml-6.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:bb4c1847b303835d89d785a18801a883436cdfd5dc3d62947f9c49e24f0f5a2c"}, + {file = "lxml-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a656ca105115f6b766bba324f23a67914d9c728dafec57638e2b92a9dcd76c62"}, + {file = "lxml-6.0.2-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c54d83a2188a10ebdba573f16bd97135d06c9ef60c3dc495315c7a28c80a263f"}, + {file = "lxml-6.0.2-cp38-cp38-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:1ea99340b3c729beea786f78c38f60f4795622f36e305d9c9be402201efdc3b7"}, + {file = "lxml-6.0.2-cp38-cp38-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:af85529ae8d2a453feee4c780d9406a5e3b17cee0dd75c18bd31adcd584debc3"}, + {file = "lxml-6.0.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fe659f6b5d10fb5a17f00a50eb903eb277a71ee35df4615db573c069bcf967ac"}, + {file = "lxml-6.0.2-cp38-cp38-win32.whl", hash = "sha256:5921d924aa5468c939d95c9814fa9f9b5935a6ff4e679e26aaf2951f74043512"}, + {file = "lxml-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:0aa7070978f893954008ab73bb9e3c24a7c56c054e00566a21b553dc18105fca"}, + {file = "lxml-6.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2c8458c2cdd29589a8367c09c8f030f1d202be673f0ca224ec18590b3b9fb694"}, + {file = "lxml-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3fee0851639d06276e6b387f1c190eb9d7f06f7f53514e966b26bae46481ec90"}, + {file = "lxml-6.0.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b2142a376b40b6736dfc214fd2902409e9e3857eff554fed2d3c60f097e62a62"}, + {file = "lxml-6.0.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a6b5b39cc7e2998f968f05309e666103b53e2edd01df8dc51b90d734c0825444"}, + {file = "lxml-6.0.2-cp39-cp39-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4aec24d6b72ee457ec665344a29acb2d35937d5192faebe429ea02633151aad"}, + {file = "lxml-6.0.2-cp39-cp39-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:b42f4d86b451c2f9d06ffb4f8bbc776e04df3ba070b9fe2657804b1b40277c48"}, + {file = "lxml-6.0.2-cp39-cp39-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cdaefac66e8b8f30e37a9b4768a391e1f8a16a7526d5bc77a7928408ef68e93"}, + {file = "lxml-6.0.2-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:b738f7e648735714bbb82bdfd030203360cfeab7f6e8a34772b3c8c8b820568c"}, + {file = "lxml-6.0.2-cp39-cp39-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:daf42de090d59db025af61ce6bdb2521f0f102ea0e6ea310f13c17610a97da4c"}, + {file = "lxml-6.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:66328dabea70b5ba7e53d94aa774b733cf66686535f3bc9250a7aab53a91caaf"}, + {file = "lxml-6.0.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:e237b807d68a61fc3b1e845407e27e5eb8ef69bc93fe8505337c1acb4ee300b6"}, + {file = "lxml-6.0.2-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:ac02dc29fd397608f8eb15ac1610ae2f2f0154b03f631e6d724d9e2ad4ee2c84"}, + {file = "lxml-6.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:817ef43a0c0b4a77bd166dc9a09a555394105ff3374777ad41f453526e37f9cb"}, + {file = "lxml-6.0.2-cp39-cp39-win32.whl", hash = "sha256:bc532422ff26b304cfb62b328826bd995c96154ffd2bac4544f37dbb95ecaa8f"}, + {file = "lxml-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:995e783eb0374c120f528f807443ad5a83a656a8624c467ea73781fc5f8a8304"}, + {file = "lxml-6.0.2-cp39-cp39-win_arm64.whl", hash = "sha256:08b9d5e803c2e4725ae9e8559ee880e5328ed61aa0935244e0515d7d9dbec0aa"}, + {file = "lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6"}, + {file = "lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba"}, + {file = "lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5"}, + {file = "lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4"}, + {file = "lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d"}, + {file = "lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d"}, + {file = "lxml-6.0.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1c06035eafa8404b5cf475bb37a9f6088b0aca288d4ccc9d69389750d5543700"}, + {file = "lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c7d13103045de1bdd6fe5d61802565f1a3537d70cd3abf596aa0af62761921ee"}, + {file = "lxml-6.0.2-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a3c150a95fbe5ac91de323aa756219ef9cf7fde5a3f00e2281e30f33fa5fa4f"}, + {file = "lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:60fa43be34f78bebb27812ed90f1925ec99560b0fa1decdb7d12b84d857d31e9"}, + {file = "lxml-6.0.2-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:21c73b476d3cfe836be731225ec3421fa2f048d84f6df6a8e70433dff1376d5a"}, + {file = "lxml-6.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:27220da5be049e936c3aca06f174e8827ca6445a4353a1995584311487fc4e3e"}, + {file = "lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62"}, +] [package.extras] cssselect = ["cssselect (>=0.7)"] +html-clean = ["lxml_html_clean"] html5 = ["html5lib"] -htmlsoup = ["beautifulsoup4"] -source = ["Cython (>=0.29.7)"] +htmlsoup = ["BeautifulSoup4"] [[package]] name = "markupsafe" -version = "2.0.1" +version = "3.0.3" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" +files = [ + {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, + {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, + {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, + {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, + {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, + {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, + {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, + {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, + {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, + {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, + {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, + {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, + {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, + {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, + {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, + {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, + {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, + {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, + {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, + {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, + {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, + {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, + {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, + {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, + {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, + {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, + {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, + {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, + {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, + {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, + {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, + {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, + {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, + {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, + {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, + {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, + {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, + {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, + {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, + {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, +] [[package]] name = "marshmallow" -version = "3.14.1" +version = "4.2.0" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.10" +files = [ + {file = "marshmallow-4.2.0-py3-none-any.whl", hash = "sha256:1dc369bd13a8708a9566d6f73d1db07d50142a7580f04fd81e1c29a4d2e10af4"}, + {file = "marshmallow-4.2.0.tar.gz", hash = "sha256:908acabd5aa14741419d3678d3296bda6abe28a167b7dcd05969ceb8256943ac"}, +] + +[package.dependencies] +backports-datetime-fromisoformat = {version = "*", markers = "python_version < \"3.11\""} +typing-extensions = {version = "*", markers = "python_version < \"3.11\""} [package.extras] -dev = ["pytest", "pytz", "simplejson", "mypy (==0.910)", "flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "pre-commit (>=2.4,<3.0)", "tox"] -docs = ["sphinx (==4.3.0)", "sphinx-issues (==1.2.0)", "alabaster (==0.7.12)", "sphinx-version-warning (==1.1.2)", "autodocsumm (==0.2.7)"] -lint = ["mypy (==0.910)", "flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "pre-commit (>=2.4,<3.0)"] -tests = ["pytest", "pytz", "simplejson"] +dev = ["marshmallow[tests]", "pre-commit (>=3.5,<5.0)", "tox"] +docs = ["autodocsumm (==0.2.14)", "furo (==2025.12.19)", "sphinx (==8.2.3)", "sphinx-copybutton (==0.5.2)", "sphinx-issues (==5.0.1)", "sphinxext-opengraph (==0.13.0)"] +tests = ["pytest", "simplejson"] [[package]] name = "mccabe" version = "0.6.1" description = "McCabe checker, plugin for flake8" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] [[package]] name = "model-mommy" version = "2.0.0" description = "Smart object creation facility for Django." -category = "dev" optional = false python-versions = "*" +files = [ + {file = "model_mommy-2.0.0-py2.py3-none-any.whl", hash = "sha256:40d6e740aad7509e696a324b94cf2b0a104da93c3d4a7924cea1be3d0eb95b4f"}, + {file = "model_mommy-2.0.0.tar.gz", hash = "sha256:3d332afce941c57f1990f45b083ba13252ba74fcd1ae43fd047e5af7a70fb312"}, +] [package.dependencies] django = ">=1.11.0" [[package]] name = "mslex" -version = "0.3.0" +version = "1.3.0" description = "shlex for windows" -category = "dev" optional = false python-versions = ">=3.5" +files = [ + {file = "mslex-1.3.0-py3-none-any.whl", hash = "sha256:c7074b347201b3466fc077c5692fbce9b5f62a63a51f537a53fbbd02eff2eea4"}, + {file = "mslex-1.3.0.tar.gz", hash = "sha256:641c887d1d3db610eee2af37a8e5abda3f70b3006cdfd2d0d29dc0d1ae28a85d"}, +] [[package]] name = "mypy" -version = "0.931" +version = "1.19.1" description = "Optional static typing for Python" -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" +files = [ + {file = "mypy-1.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f05aa3d375b385734388e844bc01733bd33c644ab48e9684faa54e5389775ec"}, + {file = "mypy-1.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:022ea7279374af1a5d78dfcab853fe6a536eebfda4b59deab53cd21f6cd9f00b"}, + {file = "mypy-1.19.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee4c11e460685c3e0c64a4c5de82ae143622410950d6be863303a1c4ba0e36d6"}, + {file = "mypy-1.19.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de759aafbae8763283b2ee5869c7255391fbc4de3ff171f8f030b5ec48381b74"}, + {file = "mypy-1.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ab43590f9cd5108f41aacf9fca31841142c786827a74ab7cc8a2eacb634e09a1"}, + {file = "mypy-1.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:2899753e2f61e571b3971747e302d5f420c3fd09650e1951e99f823bc3089dac"}, + {file = "mypy-1.19.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8dfc6ab58ca7dda47d9237349157500468e404b17213d44fc1cb77bce532288"}, + {file = "mypy-1.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e3f276d8493c3c97930e354b2595a44a21348b320d859fb4a2b9f66da9ed27ab"}, + {file = "mypy-1.19.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6"}, + {file = "mypy-1.19.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331"}, + {file = "mypy-1.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f7cee03c9a2e2ee26ec07479f38ea9c884e301d42c6d43a19d20fb014e3ba925"}, + {file = "mypy-1.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:4b84a7a18f41e167f7995200a1d07a4a6810e89d29859df936f1c3923d263042"}, + {file = "mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1"}, + {file = "mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e"}, + {file = "mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2"}, + {file = "mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8"}, + {file = "mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a"}, + {file = "mypy-1.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13"}, + {file = "mypy-1.19.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250"}, + {file = "mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b"}, + {file = "mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e"}, + {file = "mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef"}, + {file = "mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75"}, + {file = "mypy-1.19.1-cp313-cp313-win_amd64.whl", hash = "sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd"}, + {file = "mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1"}, + {file = "mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718"}, + {file = "mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b"}, + {file = "mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045"}, + {file = "mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957"}, + {file = "mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f"}, + {file = "mypy-1.19.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7bcfc336a03a1aaa26dfce9fff3e287a3ba99872a157561cbfcebe67c13308e3"}, + {file = "mypy-1.19.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b7951a701c07ea584c4fe327834b92a30825514c868b1f69c30445093fdd9d5a"}, + {file = "mypy-1.19.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b13cfdd6c87fc3efb69ea4ec18ef79c74c3f98b4e5498ca9b85ab3b2c2329a67"}, + {file = "mypy-1.19.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f28f99c824ecebcdaa2e55d82953e38ff60ee5ec938476796636b86afa3956e"}, + {file = "mypy-1.19.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c608937067d2fc5a4dd1a5ce92fd9e1398691b8c5d012d66e1ddd430e9244376"}, + {file = "mypy-1.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:409088884802d511ee52ca067707b90c883426bd95514e8cfda8281dc2effe24"}, + {file = "mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247"}, + {file = "mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba"}, +] [package.dependencies] -mypy-extensions = ">=0.4.3" -tomli = ">=1.1.0" -typing-extensions = ">=3.10" +librt = {version = ">=0.6.2", markers = "platform_python_implementation != \"PyPy\""} +mypy_extensions = ">=1.0.0" +pathspec = ">=0.9.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing_extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] -python2 = ["typed-ast (>=1.4.0,<2)"] +faster-cache = ["orjson"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] [[package]] name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." -category = "dev" +version = "1.1.0" +description = "Type system extensions for programs checked with the mypy type checker." optional = false -python-versions = "*" +python-versions = ">=3.8" +files = [ + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, +] + +[[package]] +name = "numpy" +version = "2.2.6" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.10" +files = [ + {file = "numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf"}, + {file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83"}, + {file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915"}, + {file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680"}, + {file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289"}, + {file = "numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d"}, + {file = "numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491"}, + {file = "numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a"}, + {file = "numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf"}, + {file = "numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1"}, + {file = "numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab"}, + {file = "numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47"}, + {file = "numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282"}, + {file = "numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87"}, + {file = "numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249"}, + {file = "numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49"}, + {file = "numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de"}, + {file = "numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4"}, + {file = "numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566"}, + {file = "numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f"}, + {file = "numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f"}, + {file = "numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868"}, + {file = "numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d"}, + {file = "numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd"}, + {file = "numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8"}, + {file = "numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f"}, + {file = "numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa"}, + {file = "numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571"}, + {file = "numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1"}, + {file = "numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff"}, + {file = "numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00"}, + {file = "numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd"}, +] [[package]] name = "numpy" -version = "1.22.2" -description = "NumPy is the fundamental package for array computing with Python." -category = "main" +version = "2.4.1" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.11" +files = [ + {file = "numpy-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0cce2a669e3c8ba02ee563c7835f92c153cf02edff1ae05e1823f1dde21b16a5"}, + {file = "numpy-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:899d2c18024984814ac7e83f8f49d8e8180e2fbe1b2e252f2e7f1d06bea92425"}, + {file = "numpy-2.4.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:09aa8a87e45b55a1c2c205d42e2808849ece5c484b2aab11fecabec3841cafba"}, + {file = "numpy-2.4.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:edee228f76ee2dab4579fad6f51f6a305de09d444280109e0f75df247ff21501"}, + {file = "numpy-2.4.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a92f227dbcdc9e4c3e193add1a189a9909947d4f8504c576f4a732fd0b54240a"}, + {file = "numpy-2.4.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:538bf4ec353709c765ff75ae616c34d3c3dca1a68312727e8f2676ea644f8509"}, + {file = "numpy-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ac08c63cb7779b85e9d5318e6c3518b424bc1f364ac4cb2c6136f12e5ff2dccc"}, + {file = "numpy-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f9c360ecef085e5841c539a9a12b883dff005fbd7ce46722f5e9cef52634d82"}, + {file = "numpy-2.4.1-cp311-cp311-win32.whl", hash = "sha256:0f118ce6b972080ba0758c6087c3617b5ba243d806268623dc34216d69099ba0"}, + {file = "numpy-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:18e14c4d09d55eef39a6ab5b08406e84bc6869c1e34eef45564804f90b7e0574"}, + {file = "numpy-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:6461de5113088b399d655d45c3897fa188766415d0f568f175ab071c8873bd73"}, + {file = "numpy-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d3703409aac693fa82c0aee023a1ae06a6e9d065dba10f5e8e80f642f1e9d0a2"}, + {file = "numpy-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7211b95ca365519d3596a1d8688a95874cc94219d417504d9ecb2df99fa7bfa8"}, + {file = "numpy-2.4.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5adf01965456a664fc727ed69cc71848f28d063217c63e1a0e200a118d5eec9a"}, + {file = "numpy-2.4.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:26f0bcd9c79a00e339565b303badc74d3ea2bd6d52191eeca5f95936cad107d0"}, + {file = "numpy-2.4.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0093e85df2960d7e4049664b26afc58b03236e967fb942354deef3208857a04c"}, + {file = "numpy-2.4.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ad270f438cbdd402c364980317fb6b117d9ec5e226fff5b4148dd9aa9fc6e02"}, + {file = "numpy-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:297c72b1b98100c2e8f873d5d35fb551fce7040ade83d67dd51d38c8d42a2162"}, + {file = "numpy-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf6470d91d34bf669f61d515499859fa7a4c2f7c36434afb70e82df7217933f9"}, + {file = "numpy-2.4.1-cp312-cp312-win32.whl", hash = "sha256:b6bcf39112e956594b3331316d90c90c90fb961e39696bda97b89462f5f3943f"}, + {file = "numpy-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:e1a27bb1b2dee45a2a53f5ca6ff2d1a7f135287883a1689e930d44d1ff296c87"}, + {file = "numpy-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:0e6e8f9d9ecf95399982019c01223dc130542960a12edfa8edd1122dfa66a8a8"}, + {file = "numpy-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d797454e37570cfd61143b73b8debd623c3c0952959adb817dd310a483d58a1b"}, + {file = "numpy-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82c55962006156aeef1629b953fd359064aa47e4d82cfc8e67f0918f7da3344f"}, + {file = "numpy-2.4.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:71abbea030f2cfc3092a0ff9f8c8fdefdc5e0bf7d9d9c99663538bb0ecdac0b9"}, + {file = "numpy-2.4.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5b55aa56165b17aaf15520beb9cbd33c9039810e0d9643dd4379e44294c7303e"}, + {file = "numpy-2.4.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0faba4a331195bfa96f93dd9dfaa10b2c7aa8cda3a02b7fd635e588fe821bf5"}, + {file = "numpy-2.4.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e3087f53e2b4428766b54932644d148613c5a595150533ae7f00dab2f319a8"}, + {file = "numpy-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:49e792ec351315e16da54b543db06ca8a86985ab682602d90c60ef4ff4db2a9c"}, + {file = "numpy-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79e9e06c4c2379db47f3f6fc7a8652e7498251789bf8ff5bd43bf478ef314ca2"}, + {file = "numpy-2.4.1-cp313-cp313-win32.whl", hash = "sha256:3d1a100e48cb266090a031397863ff8a30050ceefd798f686ff92c67a486753d"}, + {file = "numpy-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:92a0e65272fd60bfa0d9278e0484c2f52fe03b97aedc02b357f33fe752c52ffb"}, + {file = "numpy-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:20d4649c773f66cc2fc36f663e091f57c3b7655f936a4c681b4250855d1da8f5"}, + {file = "numpy-2.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f93bc6892fe7b0663e5ffa83b61aab510aacffd58c16e012bb9352d489d90cb7"}, + {file = "numpy-2.4.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:178de8f87948163d98a4c9ab5bee4ce6519ca918926ec8df195af582de28544d"}, + {file = "numpy-2.4.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:98b35775e03ab7f868908b524fc0a84d38932d8daf7b7e1c3c3a1b6c7a2c9f15"}, + {file = "numpy-2.4.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:941c2a93313d030f219f3a71fd3d91a728b82979a5e8034eb2e60d394a2b83f9"}, + {file = "numpy-2.4.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:529050522e983e00a6c1c6b67411083630de8b57f65e853d7b03d9281b8694d2"}, + {file = "numpy-2.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2302dc0224c1cbc49bb94f7064f3f923a971bfae45c33870dcbff63a2a550505"}, + {file = "numpy-2.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:9171a42fcad32dcf3fa86f0a4faa5e9f8facefdb276f54b8b390d90447cff4e2"}, + {file = "numpy-2.4.1-cp313-cp313t-win32.whl", hash = "sha256:382ad67d99ef49024f11d1ce5dcb5ad8432446e4246a4b014418ba3a1175a1f4"}, + {file = "numpy-2.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:62fea415f83ad8fdb6c20840578e5fbaf5ddd65e0ec6c3c47eda0f69da172510"}, + {file = "numpy-2.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:a7870e8c5fc11aef57d6fea4b4085e537a3a60ad2cdd14322ed531fdca68d261"}, + {file = "numpy-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:3869ea1ee1a1edc16c29bbe3a2f2a4e515cc3a44d43903ad41e0cacdbaf733dc"}, + {file = "numpy-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e867df947d427cdd7a60e3e271729090b0f0df80f5f10ab7dd436f40811699c3"}, + {file = "numpy-2.4.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:e3bd2cb07841166420d2fa7146c96ce00cb3410664cbc1a6be028e456c4ee220"}, + {file = "numpy-2.4.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:f0a90aba7d521e6954670550e561a4cb925713bd944445dbe9e729b71f6cabee"}, + {file = "numpy-2.4.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d558123217a83b2d1ba316b986e9248a1ed1971ad495963d555ccd75dcb1556"}, + {file = "numpy-2.4.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f44de05659b67d20499cbc96d49f2650769afcb398b79b324bb6e297bfe3844"}, + {file = "numpy-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:69e7419c9012c4aaf695109564e3387f1259f001b4326dfa55907b098af082d3"}, + {file = "numpy-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2ffd257026eb1b34352e749d7cc1678b5eeec3e329ad8c9965a797e08ccba205"}, + {file = "numpy-2.4.1-cp314-cp314-win32.whl", hash = "sha256:727c6c3275ddefa0dc078524a85e064c057b4f4e71ca5ca29a19163c607be745"}, + {file = "numpy-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:7d5d7999df434a038d75a748275cd6c0094b0ecdb0837342b332a82defc4dc4d"}, + {file = "numpy-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:ce9ce141a505053b3c7bce3216071f3bf5c182b8b28930f14cd24d43932cd2df"}, + {file = "numpy-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4e53170557d37ae404bf8d542ca5b7c629d6efa1117dac6a83e394142ea0a43f"}, + {file = "numpy-2.4.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:a73044b752f5d34d4232f25f18160a1cc418ea4507f5f11e299d8ac36875f8a0"}, + {file = "numpy-2.4.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:fb1461c99de4d040666ca0444057b06541e5642f800b71c56e6ea92d6a853a0c"}, + {file = "numpy-2.4.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:423797bdab2eeefbe608d7c1ec7b2b4fd3c58d51460f1ee26c7500a1d9c9ee93"}, + {file = "numpy-2.4.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:52b5f61bdb323b566b528899cc7db2ba5d1015bda7ea811a8bcf3c89c331fa42"}, + {file = "numpy-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42d7dd5fa36d16d52a84f821eb96031836fd405ee6955dd732f2023724d0aa01"}, + {file = "numpy-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e7b6b5e28bbd47b7532698e5db2fe1db693d84b58c254e4389d99a27bb9b8f6b"}, + {file = "numpy-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:5de60946f14ebe15e713a6f22850c2372fa72f4ff9a432ab44aa90edcadaa65a"}, + {file = "numpy-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:8f085da926c0d491ffff3096f91078cc97ea67e7e6b65e490bc8dcda65663be2"}, + {file = "numpy-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:6436cffb4f2bf26c974344439439c95e152c9a527013f26b3577be6c2ca64295"}, + {file = "numpy-2.4.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8ad35f20be147a204e28b6a0575fbf3540c5e5f802634d4258d55b1ff5facce1"}, + {file = "numpy-2.4.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:8097529164c0f3e32bb89412a0905d9100bf434d9692d9fc275e18dcf53c9344"}, + {file = "numpy-2.4.1-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:ea66d2b41ca4a1630aae5507ee0a71647d3124d1741980138aa8f28f44dac36e"}, + {file = "numpy-2.4.1-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:d3f8f0df9f4b8be57b3bf74a1d087fec68f927a2fab68231fdb442bf2c12e426"}, + {file = "numpy-2.4.1-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2023ef86243690c2791fd6353e5b4848eedaa88ca8a2d129f462049f6d484696"}, + {file = "numpy-2.4.1-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8361ea4220d763e54cff2fbe7d8c93526b744f7cd9ddab47afeff7e14e8503be"}, + {file = "numpy-2.4.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:4f1b68ff47680c2925f8063402a693ede215f0257f02596b1318ecdfb1d79e33"}, + {file = "numpy-2.4.1.tar.gz", hash = "sha256:a1ceafc5042451a858231588a104093474c6a5c57dcc724841f5c888d237d690"}, +] + +[[package]] +name = "oauthlib" +version = "3.3.1" +description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic" optional = false python-versions = ">=3.8" +files = [ + {file = "oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1"}, + {file = "oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9"}, +] + +[package.extras] +rsa = ["cryptography (>=3.0.0)"] +signals = ["blinker (>=1.4.0)"] +signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] [[package]] name = "openpyxl" -version = "3.0.9" +version = "3.1.5" description = "A Python library to read/write Excel 2010 xlsx/xlsm files" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" +files = [ + {file = "openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2"}, + {file = "openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050"}, +] [package.dependencies] et-xmlfile = "*" [[package]] name = "orderedmultidict" -version = "1.0.1" +version = "1.0.2" description = "Ordered Multivalue Dictionary" -category = "main" optional = false python-versions = "*" +files = [ + {file = "orderedmultidict-1.0.2-py2.py3-none-any.whl", hash = "sha256:ab5044c1dca4226ae4c28524cfc5cc4c939f0b49e978efa46a6ad6468049f79b"}, + {file = "orderedmultidict-1.0.2.tar.gz", hash = "sha256:16a7ae8432e02cc987d2d6d5af2df5938258f87c870675c73ee77a0920e6f4a6"}, +] [package.dependencies] six = ">=1.8.0" [[package]] name = "packaging" -version = "21.3" +version = "25.0" description = "Core utilities for Python packages" -category = "main" optional = false -python-versions = ">=3.6" - -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" +python-versions = ">=3.8" +files = [ + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, +] [[package]] name = "pandas" -version = "1.4.2" +version = "2.3.3" description = "Powerful data structures for data analysis, time series, and statistics" -category = "main" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +files = [ + {file = "pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c"}, + {file = "pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a"}, + {file = "pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1"}, + {file = "pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838"}, + {file = "pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250"}, + {file = "pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4"}, + {file = "pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826"}, + {file = "pandas-2.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:602b8615ebcc4a0c1751e71840428ddebeb142ec02c786e8ad6b1ce3c8dec523"}, + {file = "pandas-2.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8fe25fc7b623b0ef6b5009149627e34d2a4657e880948ec3c840e9402e5c1b45"}, + {file = "pandas-2.3.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b468d3dad6ff947df92dcb32ede5b7bd41a9b3cceef0a30ed925f6d01fb8fa66"}, + {file = "pandas-2.3.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b98560e98cb334799c0b07ca7967ac361a47326e9b4e5a7dfb5ab2b1c9d35a1b"}, + {file = "pandas-2.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37b5848ba49824e5c30bedb9c830ab9b7751fd049bc7914533e01c65f79791"}, + {file = "pandas-2.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db4301b2d1f926ae677a751eb2bd0e8c5f5319c9cb3f88b0becbbb0b07b34151"}, + {file = "pandas-2.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:f086f6fe114e19d92014a1966f43a3e62285109afe874f067f5abbdcbb10e59c"}, + {file = "pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53"}, + {file = "pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35"}, + {file = "pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908"}, + {file = "pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89"}, + {file = "pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98"}, + {file = "pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084"}, + {file = "pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b"}, + {file = "pandas-2.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56851a737e3470de7fa88e6131f41281ed440d29a9268dcbf0002da5ac366713"}, + {file = "pandas-2.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdcd9d1167f4885211e401b3036c0c8d9e274eee67ea8d0758a256d60704cfe8"}, + {file = "pandas-2.3.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e32e7cc9af0f1cc15548288a51a3b681cc2a219faa838e995f7dc53dbab1062d"}, + {file = "pandas-2.3.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318d77e0e42a628c04dc56bcef4b40de67918f7041c2b061af1da41dcff670ac"}, + {file = "pandas-2.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e0a175408804d566144e170d0476b15d78458795bb18f1304fb94160cabf40c"}, + {file = "pandas-2.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2d9ab0fc11822b5eece72ec9587e172f63cff87c00b062f6e37448ced4493"}, + {file = "pandas-2.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:f8bfc0e12dc78f777f323f55c58649591b2cd0c43534e8355c51d3fede5f4dee"}, + {file = "pandas-2.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:75ea25f9529fdec2d2e93a42c523962261e567d250b0013b16210e1d40d7c2e5"}, + {file = "pandas-2.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74ecdf1d301e812db96a465a525952f4dde225fdb6d8e5a521d47e1f42041e21"}, + {file = "pandas-2.3.3-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6435cb949cb34ec11cc9860246ccb2fdc9ecd742c12d3304989017d53f039a78"}, + {file = "pandas-2.3.3-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:900f47d8f20860de523a1ac881c4c36d65efcb2eb850e6948140fa781736e110"}, + {file = "pandas-2.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a45c765238e2ed7d7c608fc5bc4a6f88b642f2f01e70c0c23d2224dd21829d86"}, + {file = "pandas-2.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4fc4c21971a1a9f4bdb4c73978c7f7256caa3e62b323f70d6cb80db583350bc"}, + {file = "pandas-2.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ee15f284898e7b246df8087fc82b87b01686f98ee67d85a17b7ab44143a3a9a0"}, + {file = "pandas-2.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1611aedd912e1ff81ff41c745822980c49ce4a7907537be8692c8dbc31924593"}, + {file = "pandas-2.3.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d2cefc361461662ac48810cb14365a365ce864afe85ef1f447ff5a1e99ea81c"}, + {file = "pandas-2.3.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ee67acbbf05014ea6c763beb097e03cd629961c8a632075eeb34247120abcb4b"}, + {file = "pandas-2.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c46467899aaa4da076d5abc11084634e2d197e9460643dd455ac3db5856b24d6"}, + {file = "pandas-2.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6253c72c6a1d990a410bc7de641d34053364ef8bcd3126f7e7450125887dffe3"}, + {file = "pandas-2.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:1b07204a219b3b7350abaae088f451860223a52cfb8a6c53358e7948735158e5"}, + {file = "pandas-2.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2462b1a365b6109d275250baaae7b760fd25c726aaca0054649286bcfbb3e8ec"}, + {file = "pandas-2.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0242fe9a49aa8b4d78a4fa03acb397a58833ef6199e9aa40a95f027bb3a1b6e7"}, + {file = "pandas-2.3.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a21d830e78df0a515db2b3d2f5570610f5e6bd2e27749770e8bb7b524b89b450"}, + {file = "pandas-2.3.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e3ebdb170b5ef78f19bfb71b0dc5dc58775032361fa188e814959b74d726dd5"}, + {file = "pandas-2.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d051c0e065b94b7a3cea50eb1ec32e912cd96dba41647eb24104b6c6c14c5788"}, + {file = "pandas-2.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3869faf4bd07b3b66a9f462417d0ca3a9df29a9f6abd5d0d0dbab15dac7abe87"}, + {file = "pandas-2.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c503ba5216814e295f40711470446bc3fd00f0faea8a086cbc688808e26f92a2"}, + {file = "pandas-2.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a637c5cdfa04b6d6e2ecedcb81fc52ffb0fd78ce2ebccc9ea964df9f658de8c8"}, + {file = "pandas-2.3.3-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:854d00d556406bffe66a4c0802f334c9ad5a96b4f1f868adf036a21b11ef13ff"}, + {file = "pandas-2.3.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf1f8a81d04ca90e32a0aceb819d34dbd378a98bf923b6398b9a3ec0bf44de29"}, + {file = "pandas-2.3.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:23ebd657a4d38268c7dfbdf089fbc31ea709d82e4923c5ffd4fbd5747133ce73"}, + {file = "pandas-2.3.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5554c929ccc317d41a5e3d1234f3be588248e61f08a74dd17c9eabb535777dc9"}, + {file = "pandas-2.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:d3e28b3e83862ccf4d85ff19cf8c20b2ae7e503881711ff2d534dc8f761131aa"}, + {file = "pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b"}, +] [package.dependencies] numpy = [ - {version = ">=1.18.5", markers = "platform_machine != \"aarch64\" and platform_machine != \"arm64\" and python_version < \"3.10\""}, - {version = ">=1.19.2", markers = "platform_machine == \"aarch64\" and python_version < \"3.10\""}, - {version = ">=1.20.0", markers = "platform_machine == \"arm64\" and python_version < \"3.10\""}, - {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, + {version = ">=1.22.4", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, ] -python-dateutil = ">=2.8.1" +python-dateutil = ">=2.8.2" pytz = ">=2020.1" +tzdata = ">=2022.7" [package.extras] -test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"] +all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] +aws = ["s3fs (>=2022.11.0)"] +clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] +compression = ["zstandard (>=0.19.0)"] +computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] +consortium-standard = ["dataframe-api-compat (>=0.1.7)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] +feather = ["pyarrow (>=10.0.1)"] +fss = ["fsspec (>=2022.11.0)"] +gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] +hdf5 = ["tables (>=3.8.0)"] +html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] +mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] +parquet = ["pyarrow (>=10.0.1)"] +performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] +plot = ["matplotlib (>=3.6.3)"] +postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +pyarrow = ["pyarrow (>=10.0.1)"] +spss = ["pyreadstat (>=1.2.0)"] +sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.9.2)"] [[package]] name = "pathspec" -version = "0.9.0" +version = "1.0.3" description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.9" +files = [ + {file = "pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c"}, + {file = "pathspec-1.0.3.tar.gz", hash = "sha256:bac5cf97ae2c2876e2d25ebb15078eb04d76e4b98921ee31c6f85ade8b59444d"}, +] + +[package.extras] +hyperscan = ["hyperscan (>=0.7)"] +optional = ["typing-extensions (>=4)"] +re2 = ["google-re2 (>=1.1)"] +tests = ["pytest (>=9)", "typing-extensions (>=4.15)"] [[package]] name = "platformdirs" -version = "2.5.0" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" +version = "4.5.1" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" +files = [ + {file = "platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31"}, + {file = "platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda"}, +] + +[package.extras] +docs = ["furo (>=2025.9.25)", "proselint (>=0.14)", "sphinx (>=8.2.3)", "sphinx-autodoc-typehints (>=3.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.4.2)", "pytest-cov (>=7)", "pytest-mock (>=3.15.1)"] +type = ["mypy (>=1.18.2)"] + +[[package]] +name = "prometheus-client" +version = "0.23.1" +description = "Python client for the Prometheus monitoring system." +optional = false +python-versions = ">=3.9" +files = [ + {file = "prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99"}, + {file = "prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce"}, +] [package.extras] -docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] +twisted = ["twisted"] [[package]] name = "prompt-toolkit" -version = "3.0.28" +version = "3.0.52" description = "Library for building powerful interactive command lines in Python" -category = "main" optional = false -python-versions = ">=3.6.2" +python-versions = ">=3.8" +files = [ + {file = "prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955"}, + {file = "prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855"}, +] [package.dependencies] wcwidth = "*" +[[package]] +name = "proto-plus" +version = "1.27.0" +description = "Beautiful, Pythonic protocol buffers" +optional = false +python-versions = ">=3.7" +files = [ + {file = "proto_plus-1.27.0-py3-none-any.whl", hash = "sha256:1baa7f81cf0f8acb8bc1f6d085008ba4171eaf669629d1b6d1673b21ed1c0a82"}, + {file = "proto_plus-1.27.0.tar.gz", hash = "sha256:873af56dd0d7e91836aee871e5799e1c6f1bda86ac9a983e0bb9f0c266a568c4"}, +] + +[package.dependencies] +protobuf = ">=3.19.0,<7.0.0" + +[package.extras] +testing = ["google-api-core (>=1.31.5)"] + [[package]] name = "protobuf" -version = "3.19.4" -description = "Protocol Buffers" -category = "main" +version = "6.33.3" +description = "" optional = false -python-versions = ">=3.5" +python-versions = ">=3.9" +files = [ + {file = "protobuf-6.33.3-cp310-abi3-win32.whl", hash = "sha256:b4046f9f2ede57ad5b1d9917baafcbcad42f8151a73c755a1e2ec9557b0a764f"}, + {file = "protobuf-6.33.3-cp310-abi3-win_amd64.whl", hash = "sha256:1fd18f030ae9df97712fbbb0849b6e54c63e3edd9b88d8c3bb4771f84d8db7a4"}, + {file = "protobuf-6.33.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:648b7b0144222eb06cf529a3d7b01333c5f30b4196773b682d388f04db373759"}, + {file = "protobuf-6.33.3-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:08a6ca12f60ba99097dd3625ef4275280f99c9037990e47ce9368826b159b890"}, + {file = "protobuf-6.33.3-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:642fce7187526c98683c79a3ad68e5d646a5ef5eb004582fe123fc9a33a9456b"}, + {file = "protobuf-6.33.3-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:6fa9b5f4baa12257542273e5e6f3c3d3867b30bc2770c14ad9ac8315264bf986"}, + {file = "protobuf-6.33.3-cp39-cp39-win32.whl", hash = "sha256:c46dcc47b243b299f4f7eabeed21929c07f0d36fffe2ea8431793b53c308ab80"}, + {file = "protobuf-6.33.3-cp39-cp39-win_amd64.whl", hash = "sha256:2756963dcfd414eba46bcbb341f0e2c652036e5d700f112b3bb90fa1a031893a"}, + {file = "protobuf-6.33.3-py3-none-any.whl", hash = "sha256:c2bf221076b0d463551efa2e1319f08d4cffcc5f0d864614ccd3d0e77a637794"}, + {file = "protobuf-6.33.3.tar.gz", hash = "sha256:c8794debeb402963fddff41a595e1f649bcd76616ba56c835645cab4539e810e"}, +] [[package]] name = "psutil" -version = "5.9.0" +version = "6.1.1" description = "Cross-platform lib for process and system monitoring in Python." -category = "dev" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "psutil-6.1.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9ccc4316f24409159897799b83004cb1e24f9819b0dcf9c0b68bdcb6cefee6a8"}, + {file = "psutil-6.1.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ca9609c77ea3b8481ab005da74ed894035936223422dc591d6772b147421f777"}, + {file = "psutil-6.1.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:8df0178ba8a9e5bc84fed9cfa61d54601b371fbec5c8eebad27575f1e105c0d4"}, + {file = "psutil-6.1.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:1924e659d6c19c647e763e78670a05dbb7feaf44a0e9c94bf9e14dfc6ba50468"}, + {file = "psutil-6.1.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:018aeae2af92d943fdf1da6b58665124897cfc94faa2ca92098838f83e1b1bca"}, + {file = "psutil-6.1.1-cp27-none-win32.whl", hash = "sha256:6d4281f5bbca041e2292be3380ec56a9413b790579b8e593b1784499d0005dac"}, + {file = "psutil-6.1.1-cp27-none-win_amd64.whl", hash = "sha256:c777eb75bb33c47377c9af68f30e9f11bc78e0f07fbf907be4a5d70b2fe5f030"}, + {file = "psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8"}, + {file = "psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377"}, + {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003"}, + {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160"}, + {file = "psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3"}, + {file = "psutil-6.1.1-cp36-cp36m-win32.whl", hash = "sha256:384636b1a64b47814437d1173be1427a7c83681b17a450bfc309a1953e329603"}, + {file = "psutil-6.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8be07491f6ebe1a693f17d4f11e69d0dc1811fa082736500f649f79df7735303"}, + {file = "psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53"}, + {file = "psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649"}, + {file = "psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5"}, +] [package.extras] -test = ["ipaddress", "mock", "unittest2", "enum34", "pywin32", "wmi"] +dev = ["abi3audit", "black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"] +test = ["pytest", "pytest-xdist", "setuptools"] [[package]] name = "pyasn1" -version = "0.4.8" -description = "ASN.1 types and codecs" -category = "main" +version = "0.6.1" +description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false -python-versions = "*" +python-versions = ">=3.8" +files = [ + {file = "pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629"}, + {file = "pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034"}, +] [[package]] name = "pyasn1-modules" -version = "0.2.8" -description = "A collection of ASN.1-based protocols modules." -category = "main" +version = "0.4.2" +description = "A collection of ASN.1-based protocols modules" optional = false -python-versions = "*" +python-versions = ">=3.8" +files = [ + {file = "pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a"}, + {file = "pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6"}, +] [package.dependencies] -pyasn1 = ">=0.4.6,<0.5.0" +pyasn1 = ">=0.6.1,<0.7.0" [[package]] name = "pycodestyle" version = "2.8.0" description = "Python style guide checker" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, + {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, +] + +[[package]] +name = "pycparser" +version = "2.23" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934"}, + {file = "pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2"}, +] [[package]] name = "pydantic" -version = "1.9.0" -description = "Data validation and settings management using python 3.6 type hinting" -category = "main" +version = "2.12.5" +description = "Data validation using Python type hints" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.9" +files = [ + {file = "pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d"}, + {file = "pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49"}, +] [package.dependencies] -typing-extensions = ">=3.7.4.3" +annotated-types = ">=0.6.0" +pydantic-core = "2.41.5" +typing-extensions = ">=4.14.1" +typing-inspection = ">=0.4.2" [package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] + +[[package]] +name = "pydantic-core" +version = "2.41.5" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146"}, + {file = "pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a"}, + {file = "pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c"}, + {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2"}, + {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556"}, + {file = "pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49"}, + {file = "pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba"}, + {file = "pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9"}, + {file = "pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6"}, + {file = "pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284"}, + {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594"}, + {file = "pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e"}, + {file = "pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b"}, + {file = "pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe"}, + {file = "pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f"}, + {file = "pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7"}, + {file = "pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c"}, + {file = "pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5"}, + {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c"}, + {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294"}, + {file = "pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1"}, + {file = "pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d"}, + {file = "pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815"}, + {file = "pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3"}, + {file = "pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9"}, + {file = "pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586"}, + {file = "pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d"}, + {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740"}, + {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e"}, + {file = "pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858"}, + {file = "pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36"}, + {file = "pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11"}, + {file = "pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd"}, + {file = "pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a"}, + {file = "pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375"}, + {file = "pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553"}, + {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90"}, + {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07"}, + {file = "pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb"}, + {file = "pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23"}, + {file = "pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf"}, + {file = "pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c"}, + {file = "pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008"}, + {file = "pydantic_core-2.41.5-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:8bfeaf8735be79f225f3fefab7f941c712aaca36f1128c9d7e2352ee1aa87bdf"}, + {file = "pydantic_core-2.41.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:346285d28e4c8017da95144c7f3acd42740d637ff41946af5ce6e5e420502dd5"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75dafbf87d6276ddc5b2bf6fae5254e3d0876b626eb24969a574fff9149ee5d"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b93a4d08587e2b7e7882de461e82b6ed76d9026ce91ca7915e740ecc7855f60"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8465ab91a4bd96d36dde3263f06caa6a8a6019e4113f24dc753d79a8b3a3f82"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:299e0a22e7ae2b85c1a57f104538b2656e8ab1873511fd718a1c1c6f149b77b5"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:707625ef0983fcfb461acfaf14de2067c5942c6bb0f3b4c99158bed6fedd3cf3"}, + {file = "pydantic_core-2.41.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f41eb9797986d6ebac5e8edff36d5cef9de40def462311b3eb3eeded1431e425"}, + {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0384e2e1021894b1ff5a786dbf94771e2986ebe2869533874d7e43bc79c6f504"}, + {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:f0cd744688278965817fd0839c4a4116add48d23890d468bc436f78beb28abf5"}, + {file = "pydantic_core-2.41.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:753e230374206729bf0a807954bcc6c150d3743928a73faffee51ac6557a03c3"}, + {file = "pydantic_core-2.41.5-cp39-cp39-win32.whl", hash = "sha256:873e0d5b4fb9b89ef7c2d2a963ea7d02879d9da0da8d9d4933dee8ee86a8b460"}, + {file = "pydantic_core-2.41.5-cp39-cp39-win_amd64.whl", hash = "sha256:e4f4a984405e91527a0d62649ee21138f8e3d0ef103be488c1dc11a80d7f184b"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2"}, + {file = "pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56"}, + {file = "pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963"}, + {file = "pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f"}, + {file = "pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51"}, + {file = "pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e"}, +] + +[package.dependencies] +typing-extensions = ">=4.14.1" [[package]] name = "pyexcel" -version = "0.7.0" +version = "0.7.4" description = "A wrapper library that provides one API to read, manipulate and writedata in different excel formats" -category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "pyexcel-0.7.4-py2.py3-none-any.whl", hash = "sha256:4f287fe2cc81c1fb2c0cf7f2be018b98391229c3752fb35e7ea3d9713043f72d"}, + {file = "pyexcel-0.7.4.tar.gz", hash = "sha256:cbbdc60532bbb2a22fe4303e824aaa386ecf6dc514d1f87d1ad03a1385fee4bd"}, +] [package.dependencies] -chardet = "*" -lml = ">=0.0.4" +lml = ">=0.2.0" pyexcel-io = ">=0.6.2" texttable = ">=0.8.2" @@ -1069,27 +2634,34 @@ xlsx = ["pyexcel-xlsx (>=0.6.0)"] [[package]] name = "pyexcel-io" -version = "0.6.6" +version = "0.6.7" description = "A python library to read and write structured data in csv, zipped csvformat and to/from databases" -category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "pyexcel_io-0.6.7-py2.py3-none-any.whl", hash = "sha256:add9f3c1489070ab0a3226bab7d23d4b84a364f5b44f3a14e2ce785ede88fcb3"}, + {file = "pyexcel_io-0.6.7.tar.gz", hash = "sha256:2c33d8df505e21a13bed585ac6ab7d30ec826a9f156b758394af5d22359bddb9"}, +] [package.dependencies] lml = ">=0.0.4" [package.extras] +extra = ["chardet"] ods = ["pyexcel-ods3 (>=0.6.0)"] xls = ["pyexcel-xls (>=0.6.0)"] xlsx = ["pyexcel-xlsx (>=0.6.0)"] [[package]] name = "pyexcel-xlsx" -version = "0.6.0" +version = "0.6.1" description = "A wrapper library to read, manipulate and write data in xlsx and xlsmformat" -category = "main" optional = false python-versions = ">=3.6" +files = [ + {file = "pyexcel_xlsx-0.6.1-py2.py3-none-any.whl", hash = "sha256:c17d8c90ae6c2ae5672e469e6afe4336597e4ff479e5a93ba846ae46b7b80769"}, + {file = "pyexcel_xlsx-0.6.1.tar.gz", hash = "sha256:80b7985d394b73abf5c52212027bbbc0c7f6090192bcbc76403f8672d74c7960"}, +] [package.dependencies] openpyxl = ">=2.6.1" @@ -1099,167 +2671,398 @@ pyexcel-io = ">=0.6.2" name = "pyflakes" version = "2.4.0" description = "passive checker of Python programs" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, + {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, +] [[package]] -name = "pyparsing" -version = "3.0.7" -description = "Python parsing module" -category = "main" +name = "pyjwt" +version = "2.10.1" +description = "JSON Web Token implementation in Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" +files = [ + {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"}, + {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"}, +] + +[package.dependencies] +cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"crypto\""} [package.extras] -diagrams = ["jinja2", "railroad-diagrams"] +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 = "pyproject-flake8" -version = "0.0.1a2" +version = "0.0.1a5" description = "pyproject-flake8 (`pflake8`), a monkey patching wrapper to connect flake8 with pyproject.toml configuration" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "pyproject-flake8-0.0.1a5.tar.gz", hash = "sha256:22542080ba90d4bd80ee060852db15a24aeea61c9a29ed7c16f5b59b0e47a03a"}, + {file = "pyproject_flake8-0.0.1a5-py2.py3-none-any.whl", hash = "sha256:c843d760c49d7b270e9abda58a57765c031918a9d10da25aa43572f5d77cac43"}, +] [package.dependencies] -flake8 = "*" -toml = "*" +flake8 = "<5.0.0" +tomli = {version = "*", markers = "python_version < \"3.11\""} [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" -category = "main" 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 = "0.19.2" +version = "1.2.1" description = "Read key-value pairs from a .env file and set them as environment variables" -category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.9" +files = [ + {file = "python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61"}, + {file = "python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6"}, +] [package.extras] cli = ["click (>=5.0)"] +[[package]] +name = "python3-openid" +version = "3.2.0" +description = "OpenID support for modern servers and consumers." +optional = false +python-versions = "*" +files = [ + {file = "python3-openid-3.2.0.tar.gz", hash = "sha256:33fbf6928f401e0b790151ed2b5290b02545e8775f982485205a066f874aaeaf"}, + {file = "python3_openid-3.2.0-py3-none-any.whl", hash = "sha256:6626f771e0417486701e0b4daff762e7212e820ca5b29fcc0d05f6f8736dfa6b"}, +] + +[package.dependencies] +defusedxml = "*" + +[package.extras] +mysql = ["mysql-connector-python"] +postgresql = ["psycopg2"] + +[[package]] +name = "pytokens" +version = "0.3.0" +description = "A Fast, spec compliant Python 3.14+ tokenizer that runs on older Pythons." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3"}, + {file = "pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a"}, +] + +[package.extras] +dev = ["black", "build", "mypy", "pytest", "pytest-cov", "setuptools", "tox", "twine", "wheel"] + [[package]] name = "pytz" -version = "2021.3" +version = "2025.2" description = "World timezone definitions, modern and historical" -category = "main" optional = false python-versions = "*" +files = [ + {file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"}, + {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, + {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, + {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, + {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, + {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, + {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, + {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, + {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, + {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, + {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, + {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, + {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, + {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, + {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, + {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, + {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, + {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, + {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, + {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, + {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, + {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, + {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, + {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, + {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, + {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, + {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, + {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, + {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, + {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, + {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, + {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, + {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, + {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, + {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, + {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, + {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, + {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, + {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, + {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, +] [[package]] name = "requests" -version = "2.27.1" +version = "2.32.5" description = "Python HTTP for Humans." -category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.9" +files = [ + {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, + {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, +] [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} -idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} -urllib3 = ">=1.21.1,<1.27" +charset_normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" [package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] -name = "rsa" -version = "4.8" -description = "Pure-Python RSA implementation" -category = "main" -optional = false -python-versions = ">=3.6,<4" - -[package.dependencies] -pyasn1 = ">=0.1.3" - -[[package]] -name = "ruamel.yaml" -version = "0.17.21" -description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" -category = "main" +name = "requests-oauthlib" +version = "2.0.0" +description = "OAuthlib authentication support for Requests." optional = false -python-versions = ">=3" +python-versions = ">=3.4" +files = [ + {file = "requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9"}, + {file = "requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36"}, +] [package.dependencies] -"ruamel.yaml.clib" = {version = ">=0.2.6", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""} +oauthlib = ">=3.0.0" +requests = ">=2.0.0" [package.extras] -docs = ["ryd"] -jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] +rsa = ["oauthlib[signedtoken] (>=3.0.0)"] [[package]] -name = "ruamel.yaml.clib" -version = "0.2.6" -description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" -category = "main" +name = "rsa" +version = "4.9.1" +description = "Pure-Python RSA implementation" optional = false -python-versions = ">=3.5" +python-versions = "<4,>=3.6" +files = [ + {file = "rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762"}, + {file = "rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75"}, +] + +[package.dependencies] +pyasn1 = ">=0.1.3" [[package]] name = "s3transfer" -version = "0.5.1" +version = "0.16.0" description = "An Amazon S3 Transfer Manager" -category = "main" optional = false -python-versions = ">= 3.6" +python-versions = ">=3.9" +files = [ + {file = "s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe"}, + {file = "s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920"}, +] [package.dependencies] -botocore = ">=1.12.36,<2.0a.0" +botocore = ">=1.37.4,<2.0a.0" [package.extras] -crt = ["botocore[crt] (>=1.20.29,<2.0a.0)"] +crt = ["botocore[crt] (>=1.37.4,<2.0a.0)"] [[package]] name = "scikit-learn" -version = "1.0.2" +version = "1.7.2" description = "A set of python modules for machine learning and data mining" -category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" +files = [ + {file = "scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f"}, + {file = "scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c"}, + {file = "scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8"}, + {file = "scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18"}, + {file = "scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5"}, + {file = "scikit_learn-1.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7509693451651cd7361d30ce4e86a1347493554f172b1c72a39300fa2aea79e"}, + {file = "scikit_learn-1.7.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:0486c8f827c2e7b64837c731c8feff72c0bd2b998067a8a9cbc10643c31f0fe1"}, + {file = "scikit_learn-1.7.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89877e19a80c7b11a2891a27c21c4894fb18e2c2e077815bcade10d34287b20d"}, + {file = "scikit_learn-1.7.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8da8bf89d4d79aaec192d2bda62f9b56ae4e5b4ef93b6a56b5de4977e375c1f1"}, + {file = "scikit_learn-1.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:9b7ed8d58725030568523e937c43e56bc01cadb478fc43c042a9aca1dacb3ba1"}, + {file = "scikit_learn-1.7.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d91a97fa2b706943822398ab943cde71858a50245e31bc71dba62aab1d60a96"}, + {file = "scikit_learn-1.7.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:acbc0f5fd2edd3432a22c69bed78e837c70cf896cd7993d71d51ba6708507476"}, + {file = "scikit_learn-1.7.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5bf3d930aee75a65478df91ac1225ff89cd28e9ac7bd1196853a9229b6adb0b"}, + {file = "scikit_learn-1.7.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d6e9deed1a47aca9fe2f267ab8e8fe82ee20b4526b2c0cd9e135cea10feb44"}, + {file = "scikit_learn-1.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:6088aa475f0785e01bcf8529f55280a3d7d298679f50c0bb70a2364a82d0b290"}, + {file = "scikit_learn-1.7.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b7dacaa05e5d76759fb071558a8b5130f4845166d88654a0f9bdf3eb57851b7"}, + {file = "scikit_learn-1.7.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:abebbd61ad9e1deed54cca45caea8ad5f79e1b93173dece40bb8e0c658dbe6fe"}, + {file = "scikit_learn-1.7.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502c18e39849c0ea1a5d681af1dbcf15f6cce601aebb657aabbfe84133c1907f"}, + {file = "scikit_learn-1.7.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a4c328a71785382fe3fe676a9ecf2c86189249beff90bf85e22bdb7efaf9ae0"}, + {file = "scikit_learn-1.7.2-cp313-cp313-win_amd64.whl", hash = "sha256:63a9afd6f7b229aad94618c01c252ce9e6fa97918c5ca19c9a17a087d819440c"}, + {file = "scikit_learn-1.7.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9acb6c5e867447b4e1390930e3944a005e2cb115922e693c08a323421a6966e8"}, + {file = "scikit_learn-1.7.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:2a41e2a0ef45063e654152ec9d8bcfc39f7afce35b08902bfe290c2498a67a6a"}, + {file = "scikit_learn-1.7.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98335fb98509b73385b3ab2bd0639b1f610541d3988ee675c670371d6a87aa7c"}, + {file = "scikit_learn-1.7.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191e5550980d45449126e23ed1d5e9e24b2c68329ee1f691a3987476e115e09c"}, + {file = "scikit_learn-1.7.2-cp313-cp313t-win_amd64.whl", hash = "sha256:57dc4deb1d3762c75d685507fbd0bc17160144b2f2ba4ccea5dc285ab0d0e973"}, + {file = "scikit_learn-1.7.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fa8f63940e29c82d1e67a45d5297bdebbcb585f5a5a50c4914cc2e852ab77f33"}, + {file = "scikit_learn-1.7.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:f95dc55b7902b91331fa4e5845dd5bde0580c9cd9612b1b2791b7e80c3d32615"}, + {file = "scikit_learn-1.7.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9656e4a53e54578ad10a434dc1f993330568cfee176dff07112b8785fb413106"}, + {file = "scikit_learn-1.7.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96dc05a854add0e50d3f47a1ef21a10a595016da5b007c7d9cd9d0bffd1fcc61"}, + {file = "scikit_learn-1.7.2-cp314-cp314-win_amd64.whl", hash = "sha256:bb24510ed3f9f61476181e4db51ce801e2ba37541def12dc9333b946fc7a9cf8"}, + {file = "scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda"}, +] [package.dependencies] -joblib = ">=0.11" -numpy = ">=1.14.6" -scipy = ">=1.1.0" -threadpoolctl = ">=2.0.0" +joblib = ">=1.2.0" +numpy = ">=1.22.0" +scipy = ">=1.8.0" +threadpoolctl = ">=3.1.0" [package.extras] -benchmark = ["matplotlib (>=2.2.3)", "pandas (>=0.25.0)", "memory-profiler (>=0.57.0)"] -docs = ["matplotlib (>=2.2.3)", "scikit-image (>=0.14.5)", "pandas (>=0.25.0)", "seaborn (>=0.9.0)", "memory-profiler (>=0.57.0)", "sphinx (>=4.0.1)", "sphinx-gallery (>=0.7.0)", "numpydoc (>=1.0.0)", "Pillow (>=7.1.2)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"] -examples = ["matplotlib (>=2.2.3)", "scikit-image (>=0.14.5)", "pandas (>=0.25.0)", "seaborn (>=0.9.0)"] -tests = ["matplotlib (>=2.2.3)", "scikit-image (>=0.14.5)", "pandas (>=0.25.0)", "pytest (>=5.0.1)", "pytest-cov (>=2.9.0)", "flake8 (>=3.8.2)", "black (>=21.6b0)", "mypy (>=0.770)", "pyamg (>=4.0.0)"] +benchmark = ["matplotlib (>=3.5.0)", "memory_profiler (>=0.57.0)", "pandas (>=1.4.0)"] +build = ["cython (>=3.0.10)", "meson-python (>=0.17.1)", "numpy (>=1.22.0)", "scipy (>=1.8.0)"] +docs = ["Pillow (>=8.4.0)", "matplotlib (>=3.5.0)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.4.0)", "plotly (>=5.14.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.19.0)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-design (>=0.6.0)", "sphinx-gallery (>=0.17.1)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)", "towncrier (>=24.8.0)"] +examples = ["matplotlib (>=3.5.0)", "pandas (>=1.4.0)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.19.0)", "seaborn (>=0.9.0)"] +install = ["joblib (>=1.2.0)", "numpy (>=1.22.0)", "scipy (>=1.8.0)", "threadpoolctl (>=3.1.0)"] +maintenance = ["conda-lock (==3.0.1)"] +tests = ["matplotlib (>=3.5.0)", "mypy (>=1.15)", "numpydoc (>=1.2.0)", "pandas (>=1.4.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pyamg (>=4.2.1)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.11.7)", "scikit-image (>=0.19.0)"] [[package]] name = "scipy" -version = "1.6.1" -description = "SciPy: Scientific Library for Python" -category = "main" -optional = false -python-versions = ">=3.7" +version = "1.15.3" +description = "Fundamental algorithms for scientific computing in Python" +optional = false +python-versions = ">=3.10" +files = [ + {file = "scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c"}, + {file = "scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594"}, + {file = "scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539"}, + {file = "scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126"}, + {file = "scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5"}, + {file = "scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca"}, + {file = "scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf"}, +] [package.dependencies] -numpy = ">=1.16.5" +numpy = ">=1.23.5,<2.5" + +[package.extras] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] +doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.0.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] +test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] name = "seqeval" version = "1.2.2" description = "Testing framework for sequence labeling" -category = "main" optional = false python-versions = "*" +files = [ + {file = "seqeval-1.2.2.tar.gz", hash = "sha256:f28e97c3ab96d6fcd32b648f6438ff2e09cfba87f05939da9b3970713ec56e6f"}, +] [package.dependencies] numpy = ">=1.14.0" @@ -1267,235 +3070,463 @@ scikit-learn = ">=0.21.3" [[package]] name = "shortuuid" -version = "1.0.8" +version = "1.0.13" description = "A generator library for concise, unambiguous and URL-safe UUIDs." -category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" +files = [ + {file = "shortuuid-1.0.13-py3-none-any.whl", hash = "sha256:a482a497300b49b4953e15108a7913244e1bb0d41f9d332f5e9925dba33a3c5a"}, + {file = "shortuuid-1.0.13.tar.gz", hash = "sha256:3bb9cf07f606260584b1df46399c0b87dd84773e7b25912b7e391e30797c5e72"}, +] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, +] [[package]] name = "sqlalchemy" -version = "1.4.31" +version = "1.4.54" description = "Database Abstraction Library" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "SQLAlchemy-1.4.54-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:af00236fe21c4d4f4c227b6ccc19b44c594160cc3ff28d104cdce85855369277"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1183599e25fa38a1a322294b949da02b4f0da13dbc2688ef9dbe746df573f8a6"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1990d5a6a5dc358a0894c8ca02043fb9a5ad9538422001fb2826e91c50f1d539"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:14b3f4783275339170984cadda66e3ec011cce87b405968dc8d51cf0f9997b0d"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b24364150738ce488333b3fb48bfa14c189a66de41cd632796fbcacb26b4585"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-win32.whl", hash = "sha256:a8a72259a1652f192c68377be7011eac3c463e9892ef2948828c7d58e4829988"}, + {file = "SQLAlchemy-1.4.54-cp310-cp310-win_amd64.whl", hash = "sha256:b67589f7955924865344e6eacfdcf70675e64f36800a576aa5e961f0008cde2a"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b05e0626ec1c391432eabb47a8abd3bf199fb74bfde7cc44a26d2b1b352c2c6e"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13e91d6892b5fcb94a36ba061fb7a1f03d0185ed9d8a77c84ba389e5bb05e936"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb59a11689ff3c58e7652260127f9e34f7f45478a2f3ef831ab6db7bcd72108f"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-win32.whl", hash = "sha256:1390ca2d301a2708fd4425c6d75528d22f26b8f5cbc9faba1ddca136671432bc"}, + {file = "SQLAlchemy-1.4.54-cp311-cp311-win_amd64.whl", hash = "sha256:2b37931eac4b837c45e2522066bda221ac6d80e78922fb77c75eb12e4dbcdee5"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3f01c2629a7d6b30d8afe0326b8c649b74825a0e1ebdcb01e8ffd1c920deb07d"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c24dd161c06992ed16c5e528a75878edbaeced5660c3db88c820f1f0d3fe1f4"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5e0d47d619c739bdc636bbe007da4519fc953393304a5943e0b5aec96c9877c"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-win32.whl", hash = "sha256:12bc0141b245918b80d9d17eca94663dbd3f5266ac77a0be60750f36102bbb0f"}, + {file = "SQLAlchemy-1.4.54-cp312-cp312-win_amd64.whl", hash = "sha256:f941aaf15f47f316123e1933f9ea91a6efda73a161a6ab6046d1cde37be62c88"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:a41611835010ed4ea4c7aed1da5b58aac78ee7e70932a91ed2705a7b38e40f52"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e8c1b9ecaf9f2590337d5622189aeb2f0dbc54ba0232fa0856cf390957584a9"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0de620f978ca273ce027769dc8db7e6ee72631796187adc8471b3c76091b809e"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c5a2530400a6e7e68fd1552a55515de6a4559122e495f73554a51cedafc11669"}, + {file = "SQLAlchemy-1.4.54-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cf7076c8578b3de4e43a046cc7a1af8466e1c3f5e64167189fe8958a4f9c02"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:f1e1b92ee4ee9ffc68624ace218b89ca5ca667607ccee4541a90cc44999b9aea"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41cffc63c7c83dfc30c4cab5b4308ba74440a9633c4509c51a0c52431fb0f8ab"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5933c45d11cbd9694b1540aa9076816cc7406964c7b16a380fd84d3a5fe3241"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cafe0ba3a96d0845121433cffa2b9232844a2609fce694fcc02f3f31214ece28"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a19f816f4702d7b1951d7576026c7124b9bfb64a9543e571774cf517b7a50b29"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-win32.whl", hash = "sha256:76c2ba7b5a09863d0a8166fbc753af96d561818c572dbaf697c52095938e7be4"}, + {file = "SQLAlchemy-1.4.54-cp37-cp37m-win_amd64.whl", hash = "sha256:a86b0e4be775902a5496af4fb1b60d8a2a457d78f531458d294360b8637bb014"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:a49730afb716f3f675755afec109895cab95bc9875db7ffe2e42c1b1c6279482"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26e78444bc77d089e62874dc74df05a5c71f01ac598010a327881a48408d0064"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02d2ecb9508f16ab9c5af466dfe5a88e26adf2e1a8d1c56eb616396ccae2c186"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:394b0135900b62dbf63e4809cdc8ac923182af2816d06ea61cd6763943c2cc05"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed3576675c187e3baa80b02c4c9d0edfab78eff4e89dd9da736b921333a2432"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-win32.whl", hash = "sha256:fc9ffd9a38e21fad3e8c5a88926d57f94a32546e937e0be46142b2702003eba7"}, + {file = "SQLAlchemy-1.4.54-cp38-cp38-win_amd64.whl", hash = "sha256:a01bc25eb7a5688656c8770f931d5cb4a44c7de1b3cec69b84cc9745d1e4cc10"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:0b76bbb1cbae618d10679be8966f6d66c94f301cfc15cb49e2f2382563fb6efb"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdb2886c0be2c6c54d0651d5a61c29ef347e8eec81fd83afebbf7b59b80b7393"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:954816850777ac234a4e32b8c88ac1f7847088a6e90cfb8f0e127a1bf3feddff"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1d83cd1cc03c22d922ec94d0d5f7b7c96b1332f5e122e81b1a61fb22da77879a"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1576fba3616f79496e2f067262200dbf4aab1bb727cd7e4e006076686413c80c"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-win32.whl", hash = "sha256:3112de9e11ff1957148c6de1df2bc5cc1440ee36783412e5eedc6f53638a577d"}, + {file = "SQLAlchemy-1.4.54-cp39-cp39-win_amd64.whl", hash = "sha256:6da60fb24577f989535b8fc8b2ddc4212204aaf02e53c4c7ac94ac364150ed08"}, + {file = "sqlalchemy-1.4.54.tar.gz", hash = "sha256:4470fbed088c35dc20b78a39aaf4ae54fe81790c783b3264872a0224f437c31a"}, +] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\")"} [package.extras] -aiomysql = ["greenlet (!=0.4.17)", "aiomysql"] -aiosqlite = ["typing_extensions (!=3.10.0.1)", "greenlet (!=0.4.17)", "aiosqlite"] +aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] +aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["greenlet (!=0.4.17)", "asyncmy (>=0.2.3)"] -mariadb_connector = ["mariadb (>=1.0.1)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)", "mariadb (>=1.0.1,!=1.1.2)"] mssql = ["pyodbc"] -mssql_pymssql = ["pymssql"] -mssql_pyodbc = ["pyodbc"] -mypy = ["sqlalchemy2-stubs", "mypy (>=0.910)"] -mysql = ["mysqlclient (>=1.4.0,<2)", "mysqlclient (>=1.4.0)"] -mysql_connector = ["mysql-connector-python"] -oracle = ["cx_oracle (>=7,<8)", "cx_oracle (>=7)"] +mssql-pymssql = ["pymssql", "pymssql"] +mssql-pyodbc = ["pyodbc", "pyodbc"] +mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] +mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] +mysql-connector = ["mysql-connector-python", "mysql-connector-python"] +oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] postgresql = ["psycopg2 (>=2.7)"] -postgresql_asyncpg = ["greenlet (!=0.4.17)", "asyncpg"] -postgresql_pg8000 = ["pg8000 (>=1.16.6)"] -postgresql_psycopg2binary = ["psycopg2-binary"] -postgresql_psycopg2cffi = ["psycopg2cffi"] -pymysql = ["pymysql (<1)", "pymysql"] -sqlcipher = ["sqlcipher3-binary"] +postgresql-asyncpg = ["asyncpg", "asyncpg", "greenlet (!=0.4.17)", "greenlet (!=0.4.17)"] +postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)", "pg8000 (>=1.16.6,!=1.29.0)"] +postgresql-psycopg2binary = ["psycopg2-binary"] +postgresql-psycopg2cffi = ["psycopg2cffi"] +pymysql = ["pymysql", "pymysql (<1)"] +sqlcipher = ["sqlcipher3_binary"] [[package]] name = "sqlparse" -version = "0.4.2" +version = "0.5.5" description = "A non-validating SQL parser." -category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" +files = [ + {file = "sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba"}, + {file = "sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e"}, +] + +[package.extras] +dev = ["build"] +doc = ["sphinx"] [[package]] name = "taskipy" -version = "1.10.1" +version = "1.14.1" description = "tasks runner for python projects" -category = "dev" optional = false -python-versions = ">=3.6,<4.0" +python-versions = "<4.0,>=3.6" +files = [ + {file = "taskipy-1.14.1-py3-none-any.whl", hash = "sha256:6e361520f29a0fd2159848e953599f9c75b1d0b047461e4965069caeb94908f1"}, + {file = "taskipy-1.14.1.tar.gz", hash = "sha256:410fbcf89692dfd4b9f39c2b49e1750b0a7b81affd0e2d7ea8c35f9d6a4774ed"}, +] [package.dependencies] colorama = ">=0.4.4,<0.5.0" -mslex = {version = ">=0.3.0,<0.4.0", markers = "sys_platform == \"win32\""} -psutil = ">=5.7.2,<6.0.0" -tomli = ">=1.2.3,<2.0.0" +mslex = {version = ">=1.1.0,<2.0.0", markers = "sys_platform == \"win32\""} +psutil = ">=5.7.2,<7" +tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} [[package]] name = "texttable" -version = "1.6.4" -description = "module for creating simple ASCII tables" -category = "main" +version = "1.7.0" +description = "module to create simple ASCII tables" optional = false python-versions = "*" +files = [ + {file = "texttable-1.7.0-py2.py3-none-any.whl", hash = "sha256:72227d592c82b3d7f672731ae73e4d1f88cd8e2ef5b075a7a7f01a23a3743917"}, + {file = "texttable-1.7.0.tar.gz", hash = "sha256:2d2068fb55115807d3ac77a4ca68fa48803e84ebb0ee2340f858107a36522638"}, +] [[package]] name = "threadpoolctl" -version = "3.1.0" +version = "3.6.0" description = "threadpoolctl" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" +files = [ + {file = "threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb"}, + {file = "threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e"}, +] [[package]] name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] [[package]] name = "tomli" -version = "1.2.3" +version = "2.4.0" description = "A lil' TOML parser" -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" +files = [ + {file = "tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867"}, + {file = "tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9"}, + {file = "tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95"}, + {file = "tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76"}, + {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d"}, + {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576"}, + {file = "tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a"}, + {file = "tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa"}, + {file = "tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614"}, + {file = "tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1"}, + {file = "tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8"}, + {file = "tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a"}, + {file = "tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1"}, + {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b"}, + {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51"}, + {file = "tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729"}, + {file = "tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da"}, + {file = "tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3"}, + {file = "tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0"}, + {file = "tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e"}, + {file = "tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4"}, + {file = "tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e"}, + {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c"}, + {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f"}, + {file = "tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86"}, + {file = "tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87"}, + {file = "tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132"}, + {file = "tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6"}, + {file = "tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc"}, + {file = "tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66"}, + {file = "tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d"}, + {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702"}, + {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8"}, + {file = "tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776"}, + {file = "tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475"}, + {file = "tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2"}, + {file = "tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9"}, + {file = "tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0"}, + {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df"}, + {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d"}, + {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f"}, + {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b"}, + {file = "tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087"}, + {file = "tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd"}, + {file = "tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4"}, + {file = "tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a"}, + {file = "tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c"}, +] + +[[package]] +name = "tornado" +version = "6.5.4" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +optional = false +python-versions = ">=3.9" +files = [ + {file = "tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9"}, + {file = "tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843"}, + {file = "tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17"}, + {file = "tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335"}, + {file = "tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f"}, + {file = "tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84"}, + {file = "tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f"}, + {file = "tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8"}, + {file = "tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1"}, + {file = "tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc"}, + {file = "tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1"}, + {file = "tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7"}, +] [[package]] name = "types-chardet" -version = "4.0.3" +version = "4.0.4" description = "Typing stubs for chardet" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "types-chardet-4.0.4.tar.gz", hash = "sha256:eeb10378b44261238444d61c8e12d97d8dee151f0f4b96cc9d4ac559ca8be299"}, + {file = "types_chardet-4.0.4-py3-none-any.whl", hash = "sha256:43f7e32aba6faab0c4441075bfe7cd11807282456b913cd28c60e8ca7aeb8e4e"}, +] [[package]] name = "types-requests" -version = "2.27.10" +version = "2.32.4.20260107" description = "Typing stubs for requests" -category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.9" +files = [ + {file = "types_requests-2.32.4.20260107-py3-none-any.whl", hash = "sha256:b703fe72f8ce5b31ef031264fe9395cac8f46a04661a79f7ed31a80fb308730d"}, + {file = "types_requests-2.32.4.20260107.tar.gz", hash = "sha256:018a11ac158f801bfa84857ddec1650750e393df8a004a8a9ae2a9bec6fcb24f"}, +] [package.dependencies] -types-urllib3 = "<1.27" - -[[package]] -name = "types-urllib3" -version = "1.26.9" -description = "Typing stubs for urllib3" -category = "dev" -optional = false -python-versions = "*" +urllib3 = ">=2" [[package]] name = "types-waitress" -version = "2.0.6" +version = "2.1.4.20240421" description = "Typing stubs for waitress" -category = "dev" optional = false -python-versions = "*" +python-versions = ">=3.8" +files = [ + {file = "types-waitress-2.1.4.20240421.tar.gz", hash = "sha256:3f961b452865979ba6a09dd3ea79bcce1cfee685a01aad03766c4f9d564651c6"}, + {file = "types_waitress-2.1.4.20240421-py3-none-any.whl", hash = "sha256:0c2d39265e096add609f4d8085f1bf1721e0a91a602a1f0a9187f3f8f3a2a328"}, +] [[package]] name = "typing-extensions" -version = "4.1.1" -description = "Backported and Experimental Type Hints for Python 3.6+" -category = "main" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" +files = [ + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +files = [ + {file = "typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7"}, + {file = "typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464"}, +] + +[package.dependencies] +typing-extensions = ">=4.12.0" [[package]] name = "tzdata" -version = "2021.5" +version = "2025.3" description = "Provider of IANA time zone data" -category = "main" optional = false python-versions = ">=2" +files = [ + {file = "tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1"}, + {file = "tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7"}, +] + +[[package]] +name = "tzlocal" +version = "5.3.1" +description = "tzinfo object for the local timezone" +optional = false +python-versions = ">=3.9" +files = [ + {file = "tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d"}, + {file = "tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd"}, +] + +[package.dependencies] +tzdata = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] [[package]] name = "unittest-xml-reporting" version = "3.2.0" description = "unittest-based test runner with Ant/JUnit like XML reporting." -category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "unittest-xml-reporting-3.2.0.tar.gz", hash = "sha256:edd8d3170b40c3a81b8cf910f46c6a304ae2847ec01036d02e9c0f9b85762d28"}, + {file = "unittest_xml_reporting-3.2.0-py2.py3-none-any.whl", hash = "sha256:f3d7402e5b3ac72a5ee3149278339db1a8f932ee405f48bcb9c681372f2717d5"}, +] [package.dependencies] lxml = "*" [[package]] name = "uritemplate" -version = "4.1.1" +version = "4.2.0" description = "Implementation of RFC 6570 URI Templates" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" +files = [ + {file = "uritemplate-4.2.0-py3-none-any.whl", hash = "sha256:962201ba1c4edcab02e60f9a0d3821e82dfc5d2d6662a21abd533879bdb8a686"}, + {file = "uritemplate-4.2.0.tar.gz", hash = "sha256:480c2ed180878955863323eea31b0ede668795de182617fef9c6ca09e6ec9d0e"}, +] [[package]] name = "urllib3" -version = "1.26.8" +version = "2.6.3" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +python-versions = ">=3.9" +files = [ + {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, + {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, +] [package.extras] -brotli = ["brotlipy (>=0.6.0)"] -secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotli (>=1.2.0)", "brotlicffi (>=1.2.0.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["backports-zstd (>=1.0.0)"] [[package]] name = "vine" -version = "5.0.0" -description = "Promises, promises, promises." -category = "main" +version = "5.1.0" +description = "Python promises." optional = false python-versions = ">=3.6" +files = [ + {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, + {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, +] [[package]] name = "waitress" -version = "2.1.2" +version = "3.0.2" description = "Waitress WSGI server" -category = "main" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.9.0" +files = [ + {file = "waitress-3.0.2-py3-none-any.whl", hash = "sha256:c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e"}, + {file = "waitress-3.0.2.tar.gz", hash = "sha256:682aaaf2af0c44ada4abfb70ded36393f0e307f4ab9456a215ce0020baefc31f"}, +] [package.extras] docs = ["Sphinx (>=1.8.1)", "docutils", "pylons-sphinx-themes (>=1.0.9)"] -testing = ["pytest", "pytest-cover", "coverage (>=5.0)"] +testing = ["coverage (>=7.6.0)", "pytest", "pytest-cov"] [[package]] name = "watchdog" -version = "2.1.6" +version = "2.3.1" description = "Filesystem events monitoring" -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "watchdog-2.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1f1200d4ec53b88bf04ab636f9133cb703eb19768a39351cee649de21a33697"}, + {file = "watchdog-2.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:564e7739abd4bd348aeafbf71cc006b6c0ccda3160c7053c4a53b67d14091d42"}, + {file = "watchdog-2.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:95ad708a9454050a46f741ba5e2f3468655ea22da1114e4c40b8cbdaca572565"}, + {file = "watchdog-2.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a073c91a6ef0dda488087669586768195c3080c66866144880f03445ca23ef16"}, + {file = "watchdog-2.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa8b028750b43e80eea9946d01925168eeadb488dfdef1d82be4b1e28067f375"}, + {file = "watchdog-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:964fd236cd443933268ae49b59706569c8b741073dbfd7ca705492bae9d39aab"}, + {file = "watchdog-2.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:91fd146d723392b3e6eb1ac21f122fcce149a194a2ba0a82c5e4d0ee29cd954c"}, + {file = "watchdog-2.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efe3252137392a471a2174d721e1037a0e6a5da7beb72a021e662b7000a9903f"}, + {file = "watchdog-2.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:85bf2263290591b7c5fa01140601b64c831be88084de41efbcba6ea289874f44"}, + {file = "watchdog-2.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f2df370cd8e4e18499dd0bfdef476431bcc396108b97195d9448d90924e3131"}, + {file = "watchdog-2.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ea5d86d1bcf4a9d24610aa2f6f25492f441960cf04aed2bd9a97db439b643a7b"}, + {file = "watchdog-2.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6f5d0f7eac86807275eba40b577c671b306f6f335ba63a5c5a348da151aba0fc"}, + {file = "watchdog-2.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b848c71ef2b15d0ef02f69da8cc120d335cec0ed82a3fa7779e27a5a8527225"}, + {file = "watchdog-2.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0d9878be36d2b9271e3abaa6f4f051b363ff54dbbe7e7df1af3c920e4311ee43"}, + {file = "watchdog-2.3.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cd61f98cb37143206818cb1786d2438626aa78d682a8f2ecee239055a9771d5"}, + {file = "watchdog-2.3.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3d2dbcf1acd96e7a9c9aefed201c47c8e311075105d94ce5e899f118155709fd"}, + {file = "watchdog-2.3.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03f342a9432fe08107defbe8e405a2cb922c5d00c4c6c168c68b633c64ce6190"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7a596f9415a378d0339681efc08d2249e48975daae391d58f2e22a3673b977cf"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:0e1dd6d449267cc7d6935d7fe27ee0426af6ee16578eed93bacb1be9ff824d2d"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_i686.whl", hash = "sha256:7a1876f660e32027a1a46f8a0fa5747ad4fcf86cb451860eae61a26e102c8c79"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:2caf77ae137935c1466f8cefd4a3aec7017b6969f425d086e6a528241cba7256"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:53f3e95081280898d9e4fc51c5c69017715929e4eea1ab45801d5e903dd518ad"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:9da7acb9af7e4a272089bd2af0171d23e0d6271385c51d4d9bde91fe918c53ed"}, + {file = "watchdog-2.3.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8a4d484e846dcd75e96b96d80d80445302621be40e293bfdf34a631cab3b33dc"}, + {file = "watchdog-2.3.1-py3-none-win32.whl", hash = "sha256:a74155398434937ac2780fd257c045954de5b11b5c52fc844e2199ce3eecf4cf"}, + {file = "watchdog-2.3.1-py3-none-win_amd64.whl", hash = "sha256:5defe4f0918a2a1a4afbe4dbb967f743ac3a93d546ea4674567806375b024adb"}, + {file = "watchdog-2.3.1-py3-none-win_ia64.whl", hash = "sha256:4109cccf214b7e3462e8403ab1e5b17b302ecce6c103eb2fc3afa534a7f27b96"}, + {file = "watchdog-2.3.1.tar.gz", hash = "sha256:d9f9ed26ed22a9d331820a8432c3680707ea8b54121ddcc9dc7d9f2ceeb36906"}, +] [package.extras] watchmedo = ["PyYAML (>=3.10)"] [[package]] name = "wcwidth" -version = "0.2.5" +version = "0.2.14" description = "Measures the displayed width of unicode strings in a terminal" -category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6" +files = [ + {file = "wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1"}, + {file = "wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605"}, +] [[package]] name = "whitenoise" -version = "6.0.0" +version = "6.11.0" description = "Radically simplified static file serving for WSGI applications" -category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +files = [ + {file = "whitenoise-6.11.0-py3-none-any.whl", hash = "sha256:b2aeb45950597236f53b5342b3121c5de69c8da0109362aee506ce88e022d258"}, + {file = "whitenoise-6.11.0.tar.gz", hash = "sha256:0f5bfce6061ae6611cd9396a8231e088722e4fc67bc13a111be74c738d99375f"}, +] [package.extras] brotli = ["brotli"] @@ -1505,1089 +3536,6 @@ mssql = [] postgresql = [] [metadata] -lock-version = "1.1" -python-versions = "^3.8" -content-hash = "c1dc848d7b22c9fd7018c9b4b0782c287511db4f0c377f70ff0f06991a0fa90e" - -[metadata.files] -amqp = [ - {file = "amqp-5.0.9-py3-none-any.whl", hash = "sha256:9cd81f7b023fc04bbb108718fbac674f06901b77bfcdce85b10e2a5d0ee91be5"}, - {file = "amqp-5.0.9.tar.gz", hash = "sha256:1e5f707424e544078ca196e72ae6a14887ce74e02bd126be54b7c03c971bef18"}, -] -asgiref = [ - {file = "asgiref-3.5.0-py3-none-any.whl", hash = "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9"}, - {file = "asgiref-3.5.0.tar.gz", hash = "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0"}, -] -auto-labeling-pipeline = [ - {file = "auto-labeling-pipeline-0.1.21.tar.gz", hash = "sha256:37e7ade06fb541414dccdeaf5194d6ac59366339d562b301478b1779d7b7c9f6"}, - {file = "auto_labeling_pipeline-0.1.21-py3-none-any.whl", hash = "sha256:5813d20938aeb01268354ffbd2cb50a292590761da359b1da31f1d3f28dfc71f"}, -] -autopep8 = [ - {file = "autopep8-1.6.0-py2.py3-none-any.whl", hash = "sha256:ed77137193bbac52d029a52c59bec1b0629b5a186c495f1eb21b126ac466083f"}, - {file = "autopep8-1.6.0.tar.gz", hash = "sha256:44f0932855039d2c15c4510d6df665e4730f2b8582704fa48f9c55bd3e17d979"}, -] -"backports.zoneinfo" = [ - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, - {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, -] -billiard = [ - {file = "billiard-3.6.4.0-py3-none-any.whl", hash = "sha256:87103ea78fa6ab4d5c751c4909bcff74617d985de7fa8b672cf8618afd5a875b"}, - {file = "billiard-3.6.4.0.tar.gz", hash = "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547"}, -] -black = [ - {file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"}, - {file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"}, - {file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"}, - {file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"}, - {file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"}, - {file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"}, - {file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"}, - {file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"}, - {file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"}, - {file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"}, - {file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"}, - {file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"}, - {file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"}, - {file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"}, - {file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"}, - {file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"}, - {file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"}, - {file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"}, - {file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"}, - {file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"}, - {file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"}, - {file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"}, - {file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"}, -] -boto3 = [ - {file = "boto3-1.21.1-py3-none-any.whl", hash = "sha256:d83e0f2dad07441c8d56542f5140e8cf264b05936e7bf64c88805ebda605cab9"}, - {file = "boto3-1.21.1.tar.gz", hash = "sha256:9ce450f97e0368cf2535acfbc562b6684ca2ef4c9f58e36dda3ab0bac91f2b5e"}, -] -botocore = [ - {file = "botocore-1.24.1-py3-none-any.whl", hash = "sha256:fbeb774c4542f4e85a3348c1e9928a31da4f9d743669686fbd5290bf94e8cc03"}, - {file = "botocore-1.24.1.tar.gz", hash = "sha256:913542189e1df4487e354df942b9013ded7a5dc6c4e9f11af996a6c7d4aa6334"}, -] -cachetools = [ - {file = "cachetools-5.0.0-py3-none-any.whl", hash = "sha256:8fecd4203a38af17928be7b90689d8083603073622229ca7077b72d8e5a976e4"}, - {file = "cachetools-5.0.0.tar.gz", hash = "sha256:486471dfa8799eb7ec503a8059e263db000cdda20075ce5e48903087f79d5fd6"}, -] -celery = [ - {file = "celery-5.2.3-py3-none-any.whl", hash = "sha256:8aacd02fc23a02760686d63dde1eb0daa9f594e735e73ea8fb15c2ff15cb608c"}, - {file = "celery-5.2.3.tar.gz", hash = "sha256:e2cd41667ad97d4f6a2f4672d1c6a6ebada194c619253058b5f23704aaadaa82"}, -] -certifi = [ - {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, - {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, -] -chardet = [ - {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, - {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, -] -charset-normalizer = [ - {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, - {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, -] -click = [ - {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, - {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, -] -click-didyoumean = [ - {file = "click-didyoumean-0.3.0.tar.gz", hash = "sha256:f184f0d851d96b6d29297354ed981b7dd71df7ff500d82fa6d11f0856bee8035"}, - {file = "click_didyoumean-0.3.0-py3-none-any.whl", hash = "sha256:a0713dc7a1de3f06bc0df5a9567ad19ead2d3d5689b434768a6145bff77c0667"}, -] -click-plugins = [ - {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, - {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"}, -] -click-repl = [ - {file = "click-repl-0.2.0.tar.gz", hash = "sha256:cd12f68d745bf6151210790540b4cb064c7b13e571bc64b6957d98d120dacfd8"}, - {file = "click_repl-0.2.0-py3-none-any.whl", hash = "sha256:94b3fbbc9406a236f176e0506524b2937e4b23b6f4c0c0b2a0a83f8a64e9194b"}, -] -colorama = [ - {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, - {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, -] -coreapi = [ - {file = "coreapi-2.3.3-py2.py3-none-any.whl", hash = "sha256:bf39d118d6d3e171f10df9ede5666f63ad80bba9a29a8ec17726a66cf52ee6f3"}, - {file = "coreapi-2.3.3.tar.gz", hash = "sha256:46145fcc1f7017c076a2ef684969b641d18a2991051fddec9458ad3f78ffc1cb"}, -] -coreschema = [ - {file = "coreschema-0.0.4-py2-none-any.whl", hash = "sha256:5e6ef7bf38c1525d5e55a895934ab4273548629f16aed5c0a6caa74ebf45551f"}, - {file = "coreschema-0.0.4.tar.gz", hash = "sha256:9503506007d482ab0867ba14724b93c18a33b22b6d19fb419ef2d239dd4a1607"}, -] -coverage = [ - {file = "coverage-6.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeffd96882d8c06d31b65dddcf51db7c612547babc1c4c5db6a011abe9798525"}, - {file = "coverage-6.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:621f6ea7260ea2ffdaec64fe5cb521669984f567b66f62f81445221d4754df4c"}, - {file = "coverage-6.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84f2436d6742c01136dd940ee158bfc7cf5ced3da7e4c949662b8703b5cd8145"}, - {file = "coverage-6.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de73fca6fb403dd72d4da517cfc49fcf791f74eee697d3219f6be29adf5af6ce"}, - {file = "coverage-6.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78fbb2be068a13a5d99dce9e1e7d168db880870f7bc73f876152130575bd6167"}, - {file = "coverage-6.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f5a4551dfd09c3bd12fca8144d47fe7745275adf3229b7223c2f9e29a975ebda"}, - {file = "coverage-6.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7bff3a98f63b47464480de1b5bdd80c8fade0ba2832c9381253c9b74c4153c27"}, - {file = "coverage-6.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a06c358f4aed05fa1099c39decc8022261bb07dfadc127c08cfbd1391b09689e"}, - {file = "coverage-6.3.1-cp310-cp310-win32.whl", hash = "sha256:9fff3ff052922cb99f9e52f63f985d4f7a54f6b94287463bc66b7cdf3eb41217"}, - {file = "coverage-6.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:276b13cc085474e482566c477c25ed66a097b44c6e77132f3304ac0b039f83eb"}, - {file = "coverage-6.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:56c4a409381ddd7bbff134e9756077860d4e8a583d310a6f38a2315b9ce301d0"}, - {file = "coverage-6.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eb494070aa060ceba6e4bbf44c1bc5fa97bfb883a0d9b0c9049415f9e944793"}, - {file = "coverage-6.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e15d424b8153756b7c903bde6d4610be0c3daca3986173c18dd5c1a1625e4cd"}, - {file = "coverage-6.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d47a897c1e91f33f177c21de897267b38fbb45f2cd8e22a710bcef1df09ac1"}, - {file = "coverage-6.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:25e73d4c81efa8ea3785274a2f7f3bfbbeccb6fcba2a0bdd3be9223371c37554"}, - {file = "coverage-6.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fac0bcc5b7e8169bffa87f0dcc24435446d329cbc2b5486d155c2e0f3b493ae1"}, - {file = "coverage-6.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:72128176fea72012063200b7b395ed8a57849282b207321124d7ff14e26988e8"}, - {file = "coverage-6.3.1-cp37-cp37m-win32.whl", hash = "sha256:1bc6d709939ff262fd1432f03f080c5042dc6508b6e0d3d20e61dd045456a1a0"}, - {file = "coverage-6.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:618eeba986cea7f621d8607ee378ecc8c2504b98b3fdc4952b30fe3578304687"}, - {file = "coverage-6.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ed164af5c9078596cfc40b078c3b337911190d3faeac830c3f1274f26b8320"}, - {file = "coverage-6.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:352c68e233409c31048a3725c446a9e48bbff36e39db92774d4f2380d630d8f8"}, - {file = "coverage-6.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:448d7bde7ceb6c69e08474c2ddbc5b4cd13c9e4aa4a717467f716b5fc938a734"}, - {file = "coverage-6.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9fde6b90889522c220dd56a670102ceef24955d994ff7af2cb786b4ba8fe11e4"}, - {file = "coverage-6.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e647a0be741edbb529a72644e999acb09f2ad60465f80757da183528941ff975"}, - {file = "coverage-6.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a5cdc3adb4f8bb8d8f5e64c2e9e282bc12980ef055ec6da59db562ee9bdfefa"}, - {file = "coverage-6.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2dd70a167843b4b4b2630c0c56f1b586fe965b4f8ac5da05b6690344fd065c6b"}, - {file = "coverage-6.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9ad0a117b8dc2061ce9461ea4c1b4799e55edceb236522c5b8f958ce9ed8fa9a"}, - {file = "coverage-6.3.1-cp38-cp38-win32.whl", hash = "sha256:e92c7a5f7d62edff50f60a045dc9542bf939758c95b2fcd686175dd10ce0ed10"}, - {file = "coverage-6.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:482fb42eea6164894ff82abbcf33d526362de5d1a7ed25af7ecbdddd28fc124f"}, - {file = "coverage-6.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c5b81fb37db76ebea79aa963b76d96ff854e7662921ce742293463635a87a78d"}, - {file = "coverage-6.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a4f923b9ab265136e57cc14794a15b9dcea07a9c578609cd5dbbfff28a0d15e6"}, - {file = "coverage-6.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56d296cbc8254a7dffdd7bcc2eb70be5a233aae7c01856d2d936f5ac4e8ac1f1"}, - {file = "coverage-6.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1245ab82e8554fa88c4b2ab1e098ae051faac5af829efdcf2ce6b34dccd5567c"}, - {file = "coverage-6.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f2b05757c92ad96b33dbf8e8ec8d4ccb9af6ae3c9e9bd141c7cc44d20c6bcba"}, - {file = "coverage-6.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9e3dd806f34de38d4c01416344e98eab2437ac450b3ae39c62a0ede2f8b5e4ed"}, - {file = "coverage-6.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d651fde74a4d3122e5562705824507e2f5b2d3d57557f1916c4b27635f8fbe3f"}, - {file = "coverage-6.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:704f89b87c4f4737da2860695a18c852b78ec7279b24eedacab10b29067d3a38"}, - {file = "coverage-6.3.1-cp39-cp39-win32.whl", hash = "sha256:2aed4761809640f02e44e16b8b32c1a5dee5e80ea30a0ff0912158bde9c501f2"}, - {file = "coverage-6.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:9976fb0a5709988778ac9bc44f3d50fccd989987876dfd7716dee28beed0a9fa"}, - {file = "coverage-6.3.1-pp36.pp37.pp38-none-any.whl", hash = "sha256:463e52616ea687fd323888e86bf25e864a3cc6335a043fad6bbb037dbf49bbe2"}, - {file = "coverage-6.3.1.tar.gz", hash = "sha256:6c3f6158b02ac403868eea390930ae64e9a9a2a5bbfafefbb920d29258d9f2f8"}, -] -defusedxml = [ - {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, - {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, -] -dj-database-url = [ - {file = "dj-database-url-0.5.0.tar.gz", hash = "sha256:4aeaeb1f573c74835b0686a2b46b85990571159ffc21aa57ecd4d1e1cb334163"}, - {file = "dj_database_url-0.5.0-py2.py3-none-any.whl", hash = "sha256:851785365761ebe4994a921b433062309eb882fedd318e1b0fcecc607ed02da9"}, -] -dj-rest-auth = [ - {file = "dj-rest-auth-2.2.3.tar.gz", hash = "sha256:f292f3dffb8fc896da10adf47e94a254fb8bf42e672a066e63566363d764ad42"}, -] -django = [ - {file = "Django-4.0.6-py3-none-any.whl", hash = "sha256:ca54ebedfcbc60d191391efbf02ba68fb52165b8bf6ccd6fe71f098cac1fe59e"}, - {file = "Django-4.0.6.tar.gz", hash = "sha256:a67a793ff6827fd373555537dca0da293a63a316fe34cb7f367f898ccca3c3ae"}, -] -django-celery-results = [ - {file = "django_celery_results-2.2.0-py2.py3-none-any.whl", hash = "sha256:d5f83fad9091e52cd6dbb3ca80632153ad14b6cdac4d73258e040f92717237cb"}, - {file = "django_celery_results-2.2.0.tar.gz", hash = "sha256:cc0285090a306f97f1d4b7929ed98af0475bf6db2568976b3387de4fbe812edc"}, -] -django-cleanup = [ - {file = "django-cleanup-6.0.0.tar.gz", hash = "sha256:922e06ef8839c92bd3ab37a84db6058b8764f3fe44dbb4487bbca941d288280a"}, - {file = "django_cleanup-6.0.0-py2.py3-none-any.whl", hash = "sha256:997feab3b1f7a2e84f71c29e83b1d664459ec0d4b1924977b1fa25b5babb8703"}, -] -django-cors-headers = [ - {file = "django-cors-headers-3.11.0.tar.gz", hash = "sha256:eb98389bf7a2afc5d374806af4a9149697e3a6955b5a2dc2bf049f7d33647456"}, - {file = "django_cors_headers-3.11.0-py3-none-any.whl", hash = "sha256:a22be2befd4069c4fc174f11cf067351df5c061a3a5f94a01650b4e928b0372b"}, -] -django-drf-filepond = [ - {file = "django-drf-filepond-0.4.1.tar.gz", hash = "sha256:a32c46fd54982d88aeb4f3825973a194eb9d5d01b031c53bfe2770fc98895873"}, - {file = "django_drf_filepond-0.4.1-py2.py3-none-any.whl", hash = "sha256:e91303795d5d2f3cbb96cc28a5a6a70b5322eaa54ed7b1997ba6a7cb3a4aa609"}, -] -django-filter = [ - {file = "django-filter-21.1.tar.gz", hash = "sha256:632a251fa8f1aadb4b8cceff932bb52fe2f826dd7dfe7f3eac40e5c463d6836e"}, - {file = "django_filter-21.1-py3-none-any.whl", hash = "sha256:f4a6737a30104c98d2e2a5fb93043f36dd7978e0c7ddc92f5998e85433ea5063"}, -] -django-health-check = [ - {file = "django-health-check-3.16.5.tar.gz", hash = "sha256:1edfd49293ccebbce29f9da609c407f307aee240ab799ab4201031341ae78c0f"}, - {file = "django_health_check-3.16.5-py2.py3-none-any.whl", hash = "sha256:8d66781a0ea82b1a8b44878187b38a27370e94f18287312e39be0593e72d8983"}, -] -django-polymorphic = [ - {file = "django-polymorphic-3.1.0.tar.gz", hash = "sha256:d6955b5308bf6e41dcb22ba7c96f00b51dfa497a8a5ab1e9c06c7951bf417bf8"}, - {file = "django_polymorphic-3.1.0-py3-none-any.whl", hash = "sha256:08bc4f4f4a773a19b2deced5a56deddd1ef56ebd15207bf4052e2901c25ef57e"}, -] -django-rest-polymorphic = [ - {file = "django-rest-polymorphic-0.1.9.tar.gz", hash = "sha256:43d7f8c5b43a225fe792ac40e98d196d4c8d6872a796b61246085819b1b5f1c6"}, - {file = "django_rest_polymorphic-0.1.9-py2.py3-none-any.whl", hash = "sha256:ae9dd7a104bd6d2faac3bb7cdc31d3c3c768a4bb25f75451e866d9fab66fb6eb"}, -] -django-storages = [ - {file = "django-storages-1.12.3.tar.gz", hash = "sha256:a475edb2f0f04c4f7e548919a751ecd50117270833956ed5bd585c0575d2a5e7"}, - {file = "django_storages-1.12.3-py3-none-any.whl", hash = "sha256:204a99f218b747c46edbfeeb1310d357f83f90fa6a6024d8d0a3f422570cee84"}, -] -djangorestframework = [ - {file = "djangorestframework-3.13.1-py3-none-any.whl", hash = "sha256:24c4bf58ed7e85d1fe4ba250ab2da926d263cd57d64b03e8dcef0ac683f8b1aa"}, - {file = "djangorestframework-3.13.1.tar.gz", hash = "sha256:0c33407ce23acc68eca2a6e46424b008c9c02eceb8cf18581921d0092bc1f2ee"}, -] -djangorestframework-xml = [ - {file = "djangorestframework-xml-2.0.0.tar.gz", hash = "sha256:35f6c811d0ab8c8466b26db234e16a2ed32d76381715257aebf4c7be2c202ca1"}, - {file = "djangorestframework_xml-2.0.0-py2.py3-none-any.whl", hash = "sha256:975955fbb0d49ac44a90bdeb33b7923d95b79884d283f983e116c80a936ef4d0"}, -] -drf-yasg = [ - {file = "drf-yasg-1.20.0.tar.gz", hash = "sha256:d50f197c7f02545d0b736df88c6d5cf874f8fea2507ad85ad7de6ae5bf2d9e5a"}, - {file = "drf_yasg-1.20.0-py2.py3-none-any.whl", hash = "sha256:8b72e5b1875931a8d11af407be3a9a5ba8776541492947a0df5bafda6b7f8267"}, -] -environs = [ - {file = "environs-9.5.0-py2.py3-none-any.whl", hash = "sha256:1e549569a3de49c05f856f40bce86979e7d5ffbbc4398e7f338574c220189124"}, - {file = "environs-9.5.0.tar.gz", hash = "sha256:a76307b36fbe856bdca7ee9161e6c466fd7fcffc297109a118c59b54e27e30c9"}, -] -et-xmlfile = [ - {file = "et_xmlfile-1.1.0-py3-none-any.whl", hash = "sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada"}, - {file = "et_xmlfile-1.1.0.tar.gz", hash = "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c"}, -] -filetype = [ - {file = "filetype-1.0.10-py2.py3-none-any.whl", hash = "sha256:63fbe6e818a3d1cfac1d62b196574a7a4b7fc8e06a6c500d53577c018ef127d9"}, - {file = "filetype-1.0.10.tar.gz", hash = "sha256:323a13500731b6c65a253bc3930bbce9a56dfba71e90b60ffd968ab69d9ae937"}, -] -flake8 = [ - {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, - {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, -] -furl = [ - {file = "furl-2.1.3-py2.py3-none-any.whl", hash = "sha256:9ab425062c4217f9802508e45feb4a83e54324273ac4b202f1850363309666c0"}, - {file = "furl-2.1.3.tar.gz", hash = "sha256:5a6188fe2666c484a12159c18be97a1977a71d632ef5bb867ef15f54af39cc4e"}, -] -google-api-core = [ - {file = "google-api-core-2.7.1.tar.gz", hash = "sha256:b0fa577e512f0c8e063386b974718b8614586a798c5894ed34bedf256d9dae24"}, - {file = "google_api_core-2.7.1-py3-none-any.whl", hash = "sha256:6be1fc59e2a7ba9f66808bbc22f976f81e4c3e7ab20fa0620ce42686288787d0"}, -] -google-auth = [ - {file = "google-auth-2.6.2.tar.gz", hash = "sha256:60d449f8142c742db760f4c0be39121bc8d9be855555d784c252deaca1ced3f5"}, - {file = "google_auth-2.6.2-py2.py3-none-any.whl", hash = "sha256:3ba4d63cb29c1e6d5ffcc1c0623c03cf02ede6240a072f213084749574e691ab"}, -] -google-cloud-core = [ - {file = "google-cloud-core-2.2.3.tar.gz", hash = "sha256:89d2f7189bc6dc74de128d423ea52cc8719f0a5dbccd9ca80433f6504a20255c"}, - {file = "google_cloud_core-2.2.3-py2.py3-none-any.whl", hash = "sha256:a423852f4c36622376c8f0be509b67533690e061062368b763b92694c4ee06a7"}, -] -google-cloud-storage = [ - {file = "google-cloud-storage-2.2.1.tar.gz", hash = "sha256:0244f4612710cb5ec445fc6774387564e23f9823363fb408b28724e2102401b7"}, - {file = "google_cloud_storage-2.2.1-py2.py3-none-any.whl", hash = "sha256:abdf0fadf26516172e804e00b9c24819a3b3f7351cd32f35ca249bbfac965494"}, -] -google-crc32c = [ - {file = "google-crc32c-1.3.0.tar.gz", hash = "sha256:276de6273eb074a35bc598f8efbc00c7869c5cf2e29c90748fccc8c898c244df"}, - {file = "google_crc32c-1.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cb6994fff247987c66a8a4e550ef374671c2b82e3c0d2115e689d21e511a652d"}, - {file = "google_crc32c-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c9da0a39b53d2fab3e5467329ed50e951eb91386e9d0d5b12daf593973c3b168"}, - {file = "google_crc32c-1.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:eb0b14523758e37802f27b7f8cd973f5f3d33be7613952c0df904b68c4842f0e"}, - {file = "google_crc32c-1.3.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:95c68a4b9b7828ba0428f8f7e3109c5d476ca44996ed9a5f8aac6269296e2d59"}, - {file = "google_crc32c-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c3cf890c3c0ecfe1510a452a165431b5831e24160c5fcf2071f0f85ca5a47cd"}, - {file = "google_crc32c-1.3.0-cp310-cp310-win32.whl", hash = "sha256:3bbce1be3687bbfebe29abdb7631b83e6b25da3f4e1856a1611eb21854b689ea"}, - {file = "google_crc32c-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:c124b8c8779bf2d35d9b721e52d4adb41c9bfbde45e6a3f25f0820caa9aba73f"}, - {file = "google_crc32c-1.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:42ae4781333e331a1743445931b08ebdad73e188fd554259e772556fc4937c48"}, - {file = "google_crc32c-1.3.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ff71073ebf0e42258a42a0b34f2c09ec384977e7f6808999102eedd5b49920e3"}, - {file = "google_crc32c-1.3.0-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fe31de3002e7b08eb20823b3735b97c86c5926dd0581c7710a680b418a8709d4"}, - {file = "google_crc32c-1.3.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd7760a88a8d3d705ff562aa93f8445ead54f58fd482e4f9e2bafb7e177375d4"}, - {file = "google_crc32c-1.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a0b9e622c3b2b8d0ce32f77eba617ab0d6768b82836391e4f8f9e2074582bf02"}, - {file = "google_crc32c-1.3.0-cp36-cp36m-win32.whl", hash = "sha256:779cbf1ce375b96111db98fca913c1f5ec11b1d870e529b1dc7354b2681a8c3a"}, - {file = "google_crc32c-1.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:04e7c220798a72fd0f08242bc8d7a05986b2a08a0573396187fd32c1dcdd58b3"}, - {file = "google_crc32c-1.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e7a539b9be7b9c00f11ef16b55486141bc2cdb0c54762f84e3c6fc091917436d"}, - {file = "google_crc32c-1.3.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ca60076c388728d3b6ac3846842474f4250c91efbfe5afa872d3ffd69dd4b318"}, - {file = "google_crc32c-1.3.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05340b60bf05b574159e9bd940152a47d38af3fb43803ffe71f11d704b7696a6"}, - {file = "google_crc32c-1.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:318f73f5484b5671f0c7f5f63741ab020a599504ed81d209b5c7129ee4667407"}, - {file = "google_crc32c-1.3.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9f58099ad7affc0754ae42e6d87443299f15d739b0ce03c76f515153a5cda06c"}, - {file = "google_crc32c-1.3.0-cp37-cp37m-win32.whl", hash = "sha256:f52a4ad2568314ee713715b1e2d79ab55fab11e8b304fd1462ff5cccf4264b3e"}, - {file = "google_crc32c-1.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:bab4aebd525218bab4ee615786c4581952eadc16b1ff031813a2fd51f0cc7b08"}, - {file = "google_crc32c-1.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dda4d8a3bb0b50f540f6ff4b6033f3a74e8bf0bd5320b70fab2c03e512a62812"}, - {file = "google_crc32c-1.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fec221a051150eeddfdfcff162e6db92c65ecf46cb0f7bb1bf812a1520ec026b"}, - {file = "google_crc32c-1.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:226f2f9b8e128a6ca6a9af9b9e8384f7b53a801907425c9a292553a3a7218ce0"}, - {file = "google_crc32c-1.3.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a7f9cbea4245ee36190f85fe1814e2d7b1e5f2186381b082f5d59f99b7f11328"}, - {file = "google_crc32c-1.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a4db36f9721fdf391646685ecffa404eb986cbe007a3289499020daf72e88a2"}, - {file = "google_crc32c-1.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:12674a4c3b56b706153a358eaa1018c4137a5a04635b92b4652440d3d7386206"}, - {file = "google_crc32c-1.3.0-cp38-cp38-win32.whl", hash = "sha256:650e2917660e696041ab3dcd7abac160b4121cd9a484c08406f24c5964099829"}, - {file = "google_crc32c-1.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:58be56ae0529c664cc04a9c76e68bb92b091e0194d6e3c50bea7e0f266f73713"}, - {file = "google_crc32c-1.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:96a8918a78d5d64e07c8ea4ed2bc44354e3f93f46a4866a40e8db934e4c0d74b"}, - {file = "google_crc32c-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:13af315c3a0eec8bb8b8d80b8b128cb3fcd17d7e4edafc39647846345a3f003a"}, - {file = "google_crc32c-1.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6311853aa2bba4064d0c28ca54e7b50c4d48e3de04f6770f6c60ebda1e975267"}, - {file = "google_crc32c-1.3.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ed447680ff21c14aaceb6a9f99a5f639f583ccfe4ce1a5e1d48eb41c3d6b3217"}, - {file = "google_crc32c-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1c1d6236feab51200272d79b3d3e0f12cf2cbb12b208c835b175a21efdb0a73"}, - {file = "google_crc32c-1.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e0f1ff55dde0ebcfbef027edc21f71c205845585fffe30d4ec4979416613e9b3"}, - {file = "google_crc32c-1.3.0-cp39-cp39-win32.whl", hash = "sha256:fbd60c6aaa07c31d7754edbc2334aef50601b7f1ada67a96eb1eb57c7c72378f"}, - {file = "google_crc32c-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:127f9cc3ac41b6a859bd9dc4321097b1a4f6aa7fdf71b4f9227b9e3ebffb4422"}, - {file = "google_crc32c-1.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fc28e0db232c62ca0c3600884933178f0825c99be4474cdd645e378a10588125"}, - {file = "google_crc32c-1.3.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1926fd8de0acb9d15ee757175ce7242e235482a783cd4ec711cc999fc103c24e"}, - {file = "google_crc32c-1.3.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5da2c81575cc3ccf05d9830f9e8d3c70954819ca9a63828210498c0774fda1a3"}, - {file = "google_crc32c-1.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:891f712ce54e0d631370e1f4997b3f182f3368179198efc30d477c75d1f44942"}, - {file = "google_crc32c-1.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:7f6fe42536d9dcd3e2ffb9d3053f5d05221ae3bbcefbe472bdf2c71c793e3183"}, -] -google-resumable-media = [ - {file = "google-resumable-media-2.3.2.tar.gz", hash = "sha256:06924e8b1e79f158f0202e7dd151ad75b0ea9d59b997c850f56bdd4a5a361513"}, - {file = "google_resumable_media-2.3.2-py2.py3-none-any.whl", hash = "sha256:3c13f84813861ac8f5b6371254bdd437076bf1f3bac527a9f3fd123a70166f52"}, -] -googleapis-common-protos = [ - {file = "googleapis-common-protos-1.56.0.tar.gz", hash = "sha256:4007500795bcfc269d279f0f7d253ae18d6dc1ff5d5a73613ffe452038b1ec5f"}, - {file = "googleapis_common_protos-1.56.0-py2.py3-none-any.whl", hash = "sha256:60220c89b8bd5272159bed4929ecdc1243ae1f73437883a499a44a1cbc084086"}, -] -greenlet = [ - {file = "greenlet-1.1.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:58df5c2a0e293bf665a51f8a100d3e9956febfbf1d9aaf8c0677cf70218910c6"}, - {file = "greenlet-1.1.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:aec52725173bd3a7b56fe91bc56eccb26fbdff1386ef123abb63c84c5b43b63a"}, - {file = "greenlet-1.1.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:833e1551925ed51e6b44c800e71e77dacd7e49181fdc9ac9a0bf3714d515785d"}, - {file = "greenlet-1.1.2-cp27-cp27m-win32.whl", hash = "sha256:aa5b467f15e78b82257319aebc78dd2915e4c1436c3c0d1ad6f53e47ba6e2713"}, - {file = "greenlet-1.1.2-cp27-cp27m-win_amd64.whl", hash = "sha256:40b951f601af999a8bf2ce8c71e8aaa4e8c6f78ff8afae7b808aae2dc50d4c40"}, - {file = "greenlet-1.1.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:95e69877983ea39b7303570fa6760f81a3eec23d0e3ab2021b7144b94d06202d"}, - {file = "greenlet-1.1.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:356b3576ad078c89a6107caa9c50cc14e98e3a6c4874a37c3e0273e4baf33de8"}, - {file = "greenlet-1.1.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8639cadfda96737427330a094476d4c7a56ac03de7265622fcf4cfe57c8ae18d"}, - {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497"}, - {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1"}, - {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58"}, - {file = "greenlet-1.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b336501a05e13b616ef81ce329c0e09ac5ed8c732d9ba7e3e983fcc1a9e86965"}, - {file = "greenlet-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708"}, - {file = "greenlet-1.1.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23"}, - {file = "greenlet-1.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee"}, - {file = "greenlet-1.1.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:fa877ca7f6b48054f847b61d6fa7bed5cebb663ebc55e018fda12db09dcc664c"}, - {file = "greenlet-1.1.2-cp35-cp35m-win32.whl", hash = "sha256:7cbd7574ce8e138bda9df4efc6bf2ab8572c9aff640d8ecfece1b006b68da963"}, - {file = "greenlet-1.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:903bbd302a2378f984aef528f76d4c9b1748f318fe1294961c072bdc7f2ffa3e"}, - {file = "greenlet-1.1.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:049fe7579230e44daef03a259faa24511d10ebfa44f69411d99e6a184fe68073"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:dd0b1e9e891f69e7675ba5c92e28b90eaa045f6ab134ffe70b52e948aa175b3c"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7418b6bfc7fe3331541b84bb2141c9baf1ec7132a7ecd9f375912eca810e714e"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08"}, - {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168"}, - {file = "greenlet-1.1.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b8c008de9d0daba7b6666aa5bbfdc23dcd78cafc33997c9b7741ff6353bafb7f"}, - {file = "greenlet-1.1.2-cp36-cp36m-win32.whl", hash = "sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa"}, - {file = "greenlet-1.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d"}, - {file = "greenlet-1.1.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fdcec0b8399108577ec290f55551d926d9a1fa6cad45882093a7a07ac5ec147b"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:93f81b134a165cc17123626ab8da2e30c0455441d4ab5576eed73a64c025b25c"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28"}, - {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5"}, - {file = "greenlet-1.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c5d5b35f789a030ebb95bff352f1d27a93d81069f2adb3182d99882e095cefe"}, - {file = "greenlet-1.1.2-cp37-cp37m-win32.whl", hash = "sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc"}, - {file = "greenlet-1.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06"}, - {file = "greenlet-1.1.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:eb6ea6da4c787111adf40f697b4e58732ee0942b5d3bd8f435277643329ba627"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:f3acda1924472472ddd60c29e5b9db0cec629fbe3c5c5accb74d6d6d14773478"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711"}, - {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b"}, - {file = "greenlet-1.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2bde6792f313f4e918caabc46532aa64aa27a0db05d75b20edfc5c6f46479de2"}, - {file = "greenlet-1.1.2-cp38-cp38-win32.whl", hash = "sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd"}, - {file = "greenlet-1.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3"}, - {file = "greenlet-1.1.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:572e1787d1460da79590bf44304abbc0a2da944ea64ec549188fa84d89bba7ab"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:be5f425ff1f5f4b3c1e33ad64ab994eed12fc284a6ea71c5243fd564502ecbe5"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b"}, - {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3"}, - {file = "greenlet-1.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0051c6f1f27cb756ffc0ffbac7d2cd48cb0362ac1736871399a739b2885134d3"}, - {file = "greenlet-1.1.2-cp39-cp39-win32.whl", hash = "sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf"}, - {file = "greenlet-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd"}, - {file = "greenlet-1.1.2.tar.gz", hash = "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a"}, -] -gunicorn = [ - {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, - {file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"}, -] -idna = [ - {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, - {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, -] -inflection = [ - {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"}, - {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"}, -] -isort = [ - {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, - {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, -] -itypes = [ - {file = "itypes-1.2.0-py2.py3-none-any.whl", hash = "sha256:03da6872ca89d29aef62773672b2d408f490f80db48b23079a4b194c86dd04c6"}, - {file = "itypes-1.2.0.tar.gz", hash = "sha256:af886f129dea4a2a1e3d36595a2d139589e4dd287f5cab0b40e799ee81570ff1"}, -] -jinja2 = [ - {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, - {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, -] -jmespath = [ - {file = "jmespath-0.10.0-py2.py3-none-any.whl", hash = "sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f"}, - {file = "jmespath-0.10.0.tar.gz", hash = "sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9"}, -] -joblib = [ - {file = "joblib-1.1.0-py2.py3-none-any.whl", hash = "sha256:f21f109b3c7ff9d95f8387f752d0d9c34a02aa2f7060c2135f465da0e5160ff6"}, - {file = "joblib-1.1.0.tar.gz", hash = "sha256:4158fcecd13733f8be669be0683b96ebdbbd38d23559f54dca7205aea1bf1e35"}, -] -kombu = [ - {file = "kombu-5.2.3-py3-none-any.whl", hash = "sha256:eeaeb8024f3a5cfc71c9250e45cddb8493f269d74ada2f74909a93c59c4b4179"}, - {file = "kombu-5.2.3.tar.gz", hash = "sha256:81a90c1de97e08d3db37dbf163eaaf667445e1068c98bfd89f051a40e9f6dbbd"}, -] -lml = [ - {file = "lml-0.1.0-py2.py3-none-any.whl", hash = "sha256:ec06e850019942a485639c8c2a26bdb99eae24505bee7492b649df98a0bed101"}, - {file = "lml-0.1.0.tar.gz", hash = "sha256:57a085a29bb7991d70d41c6c3144c560a8e35b4c1030ffb36d85fa058773bcc5"}, -] -lxml = [ - {file = "lxml-4.9.1-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:98cafc618614d72b02185ac583c6f7796202062c41d2eeecdf07820bad3295ed"}, - {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c62e8dd9754b7debda0c5ba59d34509c4688f853588d75b53c3791983faa96fc"}, - {file = "lxml-4.9.1-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:21fb3d24ab430fc538a96e9fbb9b150029914805d551deeac7d7822f64631dfc"}, - {file = "lxml-4.9.1-cp27-cp27m-win32.whl", hash = "sha256:86e92728ef3fc842c50a5cb1d5ba2bc66db7da08a7af53fb3da79e202d1b2cd3"}, - {file = "lxml-4.9.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4cfbe42c686f33944e12f45a27d25a492cc0e43e1dc1da5d6a87cbcaf2e95627"}, - {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dad7b164905d3e534883281c050180afcf1e230c3d4a54e8038aa5cfcf312b84"}, - {file = "lxml-4.9.1-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a614e4afed58c14254e67862456d212c4dcceebab2eaa44d627c2ca04bf86837"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f9ced82717c7ec65a67667bb05865ffe38af0e835cdd78728f1209c8fffe0cad"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:d9fc0bf3ff86c17348dfc5d322f627d78273eba545db865c3cd14b3f19e57fa5"}, - {file = "lxml-4.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e5f66bdf0976ec667fc4594d2812a00b07ed14d1b44259d19a41ae3fff99f2b8"}, - {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fe17d10b97fdf58155f858606bddb4e037b805a60ae023c009f760d8361a4eb8"}, - {file = "lxml-4.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8caf4d16b31961e964c62194ea3e26a0e9561cdf72eecb1781458b67ec83423d"}, - {file = "lxml-4.9.1-cp310-cp310-win32.whl", hash = "sha256:4780677767dd52b99f0af1f123bc2c22873d30b474aa0e2fc3fe5e02217687c7"}, - {file = "lxml-4.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:b122a188cd292c4d2fcd78d04f863b789ef43aa129b233d7c9004de08693728b"}, - {file = "lxml-4.9.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:be9eb06489bc975c38706902cbc6888f39e946b81383abc2838d186f0e8b6a9d"}, - {file = "lxml-4.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f1be258c4d3dc609e654a1dc59d37b17d7fef05df912c01fc2e15eb43a9735f3"}, - {file = "lxml-4.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:927a9dd016d6033bc12e0bf5dee1dde140235fc8d0d51099353c76081c03dc29"}, - {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9232b09f5efee6a495a99ae6824881940d6447debe272ea400c02e3b68aad85d"}, - {file = "lxml-4.9.1-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:04da965dfebb5dac2619cb90fcf93efdb35b3c6994fea58a157a834f2f94b318"}, - {file = "lxml-4.9.1-cp35-cp35m-win32.whl", hash = "sha256:4d5bae0a37af799207140652a700f21a85946f107a199bcb06720b13a4f1f0b7"}, - {file = "lxml-4.9.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4878e667ebabe9b65e785ac8da4d48886fe81193a84bbe49f12acff8f7a383a4"}, - {file = "lxml-4.9.1-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:1355755b62c28950f9ce123c7a41460ed9743c699905cbe664a5bcc5c9c7c7fb"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:bcaa1c495ce623966d9fc8a187da80082334236a2a1c7e141763ffaf7a405067"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6eafc048ea3f1b3c136c71a86db393be36b5b3d9c87b1c25204e7d397cee9536"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:13c90064b224e10c14dcdf8086688d3f0e612db53766e7478d7754703295c7c8"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206a51077773c6c5d2ce1991327cda719063a47adc02bd703c56a662cdb6c58b"}, - {file = "lxml-4.9.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e8f0c9d65da595cfe91713bc1222af9ecabd37971762cb830dea2fc3b3bb2acf"}, - {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8f0a4d179c9a941eb80c3a63cdb495e539e064f8054230844dcf2fcb812b71d3"}, - {file = "lxml-4.9.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:830c88747dce8a3e7525defa68afd742b4580df6aa2fdd6f0855481e3994d391"}, - {file = "lxml-4.9.1-cp36-cp36m-win32.whl", hash = "sha256:1e1cf47774373777936c5aabad489fef7b1c087dcd1f426b621fda9dcc12994e"}, - {file = "lxml-4.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:5974895115737a74a00b321e339b9c3f45c20275d226398ae79ac008d908bff7"}, - {file = "lxml-4.9.1-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:1423631e3d51008871299525b541413c9b6c6423593e89f9c4cfbe8460afc0a2"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:2aaf6a0a6465d39b5ca69688fce82d20088c1838534982996ec46633dc7ad6cc"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:9f36de4cd0c262dd9927886cc2305aa3f2210db437aa4fed3fb4940b8bf4592c"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae06c1e4bc60ee076292e582a7512f304abdf6c70db59b56745cca1684f875a4"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:57e4d637258703d14171b54203fd6822fda218c6c2658a7d30816b10995f29f3"}, - {file = "lxml-4.9.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6d279033bf614953c3fc4a0aa9ac33a21e8044ca72d4fa8b9273fe75359d5cca"}, - {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a60f90bba4c37962cbf210f0188ecca87daafdf60271f4c6948606e4dabf8785"}, - {file = "lxml-4.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6ca2264f341dd81e41f3fffecec6e446aa2121e0b8d026fb5130e02de1402785"}, - {file = "lxml-4.9.1-cp37-cp37m-win32.whl", hash = "sha256:27e590352c76156f50f538dbcebd1925317a0f70540f7dc8c97d2931c595783a"}, - {file = "lxml-4.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:eea5d6443b093e1545ad0210e6cf27f920482bfcf5c77cdc8596aec73523bb7e"}, - {file = "lxml-4.9.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f05251bbc2145349b8d0b77c0d4e5f3b228418807b1ee27cefb11f69ed3d233b"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:487c8e61d7acc50b8be82bda8c8d21d20e133c3cbf41bd8ad7eb1aaeb3f07c97"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d1a92d8e90b286d491e5626af53afef2ba04da33e82e30744795c71880eaa21"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:b570da8cd0012f4af9fa76a5635cd31f707473e65a5a335b186069d5c7121ff2"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5ef87fca280fb15342726bd5f980f6faf8b84a5287fcc2d4962ea8af88b35130"}, - {file = "lxml-4.9.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:93e414e3206779ef41e5ff2448067213febf260ba747fc65389a3ddaa3fb8715"}, - {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6653071f4f9bac46fbc30f3c7838b0e9063ee335908c5d61fb7a4a86c8fd2036"}, - {file = "lxml-4.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:32a73c53783becdb7eaf75a2a1525ea8e49379fb7248c3eeefb9412123536387"}, - {file = "lxml-4.9.1-cp38-cp38-win32.whl", hash = "sha256:1a7c59c6ffd6ef5db362b798f350e24ab2cfa5700d53ac6681918f314a4d3b94"}, - {file = "lxml-4.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:1436cf0063bba7888e43f1ba8d58824f085410ea2025befe81150aceb123e345"}, - {file = "lxml-4.9.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:4beea0f31491bc086991b97517b9683e5cfb369205dac0148ef685ac12a20a67"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:41fb58868b816c202e8881fd0f179a4644ce6e7cbbb248ef0283a34b73ec73bb"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:bd34f6d1810d9354dc7e35158aa6cc33456be7706df4420819af6ed966e85448"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:edffbe3c510d8f4bf8640e02ca019e48a9b72357318383ca60e3330c23aaffc7"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d949f53ad4fc7cf02c44d6678e7ff05ec5f5552b235b9e136bd52e9bf730b91"}, - {file = "lxml-4.9.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:079b68f197c796e42aa80b1f739f058dcee796dc725cc9a1be0cdb08fc45b000"}, - {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9c3a88d20e4fe4a2a4a84bf439a5ac9c9aba400b85244c63a1ab7088f85d9d25"}, - {file = "lxml-4.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4e285b5f2bf321fc0857b491b5028c5f276ec0c873b985d58d7748ece1d770dd"}, - {file = "lxml-4.9.1-cp39-cp39-win32.whl", hash = "sha256:ef72013e20dd5ba86a8ae1aed7f56f31d3374189aa8b433e7b12ad182c0d2dfb"}, - {file = "lxml-4.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:10d2017f9150248563bb579cd0d07c61c58da85c922b780060dcc9a3aa9f432d"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538747a9d7827ce3e16a8fdd201a99e661c7dee3c96c885d8ecba3c35d1032c"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0645e934e940107e2fdbe7c5b6fb8ec6232444260752598bc4d09511bd056c0b"}, - {file = "lxml-4.9.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6daa662aba22ef3258934105be2dd9afa5bb45748f4f702a3b39a5bf53a1f4dc"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:603a464c2e67d8a546ddaa206d98e3246e5db05594b97db844c2f0a1af37cf5b"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c4b2e0559b68455c085fb0f6178e9752c4be3bba104d6e881eb5573b399d1eb2"}, - {file = "lxml-4.9.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0f3f0059891d3254c7b5fb935330d6db38d6519ecd238ca4fce93c234b4a0f73"}, - {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c852b1530083a620cb0de5f3cd6826f19862bafeaf77586f1aef326e49d95f0c"}, - {file = "lxml-4.9.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:287605bede6bd36e930577c5925fcea17cb30453d96a7b4c63c14a257118dbb9"}, - {file = "lxml-4.9.1.tar.gz", hash = "sha256:fe749b052bb7233fe5d072fcb549221a8cb1a16725c47c37e42b0b9cb3ff2c3f"}, -] -markupsafe = [ - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, - {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, -] -marshmallow = [ - {file = "marshmallow-3.14.1-py3-none-any.whl", hash = "sha256:04438610bc6dadbdddb22a4a55bcc7f6f8099e69580b2e67f5a681933a1f4400"}, - {file = "marshmallow-3.14.1.tar.gz", hash = "sha256:4c05c1684e0e97fe779c62b91878f173b937fe097b356cd82f793464f5bc6138"}, -] -mccabe = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, -] -model-mommy = [ - {file = "model_mommy-2.0.0-py2.py3-none-any.whl", hash = "sha256:40d6e740aad7509e696a324b94cf2b0a104da93c3d4a7924cea1be3d0eb95b4f"}, - {file = "model_mommy-2.0.0.tar.gz", hash = "sha256:3d332afce941c57f1990f45b083ba13252ba74fcd1ae43fd047e5af7a70fb312"}, -] -mslex = [ - {file = "mslex-0.3.0-py2.py3-none-any.whl", hash = "sha256:380cb14abf8fabf40e56df5c8b21a6d533dc5cbdcfe42406bbf08dda8f42e42a"}, - {file = "mslex-0.3.0.tar.gz", hash = "sha256:4a1ac3f25025cad78ad2fe499dd16d42759f7a3801645399cce5c404415daa97"}, -] -mypy = [ - {file = "mypy-0.931-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3c5b42d0815e15518b1f0990cff7a705805961613e701db60387e6fb663fe78a"}, - {file = "mypy-0.931-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c89702cac5b302f0c5d33b172d2b55b5df2bede3344a2fbed99ff96bddb2cf00"}, - {file = "mypy-0.931-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:300717a07ad09525401a508ef5d105e6b56646f7942eb92715a1c8d610149714"}, - {file = "mypy-0.931-cp310-cp310-win_amd64.whl", hash = "sha256:7b3f6f557ba4afc7f2ce6d3215d5db279bcf120b3cfd0add20a5d4f4abdae5bc"}, - {file = "mypy-0.931-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1bf752559797c897cdd2c65f7b60c2b6969ffe458417b8d947b8340cc9cec08d"}, - {file = "mypy-0.931-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4365c60266b95a3f216a3047f1d8e3f895da6c7402e9e1ddfab96393122cc58d"}, - {file = "mypy-0.931-cp36-cp36m-win_amd64.whl", hash = "sha256:1b65714dc296a7991000b6ee59a35b3f550e0073411ac9d3202f6516621ba66c"}, - {file = "mypy-0.931-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e839191b8da5b4e5d805f940537efcaa13ea5dd98418f06dc585d2891d228cf0"}, - {file = "mypy-0.931-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:50c7346a46dc76a4ed88f3277d4959de8a2bd0a0fa47fa87a4cde36fe247ac05"}, - {file = "mypy-0.931-cp37-cp37m-win_amd64.whl", hash = "sha256:d8f1ff62f7a879c9fe5917b3f9eb93a79b78aad47b533911b853a757223f72e7"}, - {file = "mypy-0.931-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9fe20d0872b26c4bba1c1be02c5340de1019530302cf2dcc85c7f9fc3252ae0"}, - {file = "mypy-0.931-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1b06268df7eb53a8feea99cbfff77a6e2b205e70bf31743e786678ef87ee8069"}, - {file = "mypy-0.931-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8c11003aaeaf7cc2d0f1bc101c1cc9454ec4cc9cb825aef3cafff8a5fdf4c799"}, - {file = "mypy-0.931-cp38-cp38-win_amd64.whl", hash = "sha256:d9d2b84b2007cea426e327d2483238f040c49405a6bf4074f605f0156c91a47a"}, - {file = "mypy-0.931-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ff3bf387c14c805ab1388185dd22d6b210824e164d4bb324b195ff34e322d166"}, - {file = "mypy-0.931-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5b56154f8c09427bae082b32275a21f500b24d93c88d69a5e82f3978018a0266"}, - {file = "mypy-0.931-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8ca7f8c4b1584d63c9a0f827c37ba7a47226c19a23a753d52e5b5eddb201afcd"}, - {file = "mypy-0.931-cp39-cp39-win_amd64.whl", hash = "sha256:74f7eccbfd436abe9c352ad9fb65872cc0f1f0a868e9d9c44db0893440f0c697"}, - {file = "mypy-0.931-py3-none-any.whl", hash = "sha256:1171f2e0859cfff2d366da2c7092b06130f232c636a3f7301e3feb8b41f6377d"}, - {file = "mypy-0.931.tar.gz", hash = "sha256:0038b21890867793581e4cb0d810829f5fd4441aa75796b53033af3aa30430ce"}, -] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] -numpy = [ - {file = "numpy-1.22.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:515a8b6edbb904594685da6e176ac9fbea8f73a5ebae947281de6613e27f1956"}, - {file = "numpy-1.22.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:76a4f9bce0278becc2da7da3b8ef854bed41a991f4226911a24a9711baad672c"}, - {file = "numpy-1.22.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:168259b1b184aa83a514f307352c25c56af111c269ffc109d9704e81f72e764b"}, - {file = "numpy-1.22.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3556c5550de40027d3121ebbb170f61bbe19eb639c7ad0c7b482cd9b560cd23b"}, - {file = "numpy-1.22.2-cp310-cp310-win_amd64.whl", hash = "sha256:aafa46b5a39a27aca566198d3312fb3bde95ce9677085efd02c86f7ef6be4ec7"}, - {file = "numpy-1.22.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:55535c7c2f61e2b2fc817c5cbe1af7cb907c7f011e46ae0a52caa4be1f19afe2"}, - {file = "numpy-1.22.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:60cb8e5933193a3cc2912ee29ca331e9c15b2da034f76159b7abc520b3d1233a"}, - {file = "numpy-1.22.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b536b6840e84c1c6a410f3a5aa727821e6108f3454d81a5cd5900999ef04f89"}, - {file = "numpy-1.22.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2638389562bda1635b564490d76713695ff497242a83d9b684d27bb4a6cc9d7a"}, - {file = "numpy-1.22.2-cp38-cp38-win32.whl", hash = "sha256:6767ad399e9327bfdbaa40871be4254d1995f4a3ca3806127f10cec778bd9896"}, - {file = "numpy-1.22.2-cp38-cp38-win_amd64.whl", hash = "sha256:03ae5850619abb34a879d5f2d4bb4dcd025d6d8fb72f5e461dae84edccfe129f"}, - {file = "numpy-1.22.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:d76a26c5118c4d96e264acc9e3242d72e1a2b92e739807b3b69d8d47684b6677"}, - {file = "numpy-1.22.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:15efb7b93806d438e3bc590ca8ef2f953b0ce4f86f337ef4559d31ec6cf9d7dd"}, - {file = "numpy-1.22.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:badca914580eb46385e7f7e4e426fea6de0a37b9e06bec252e481ae7ec287082"}, - {file = "numpy-1.22.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94dd11d9f13ea1be17bac39c1942f527cbf7065f94953cf62dfe805653da2f8f"}, - {file = "numpy-1.22.2-cp39-cp39-win32.whl", hash = "sha256:8cf33634b60c9cef346663a222d9841d3bbbc0a2f00221d6bcfd0d993d5543f6"}, - {file = "numpy-1.22.2-cp39-cp39-win_amd64.whl", hash = "sha256:59153979d60f5bfe9e4c00e401e24dfe0469ef8da6d68247439d3278f30a180f"}, - {file = "numpy-1.22.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a176959b6e7e00b5a0d6f549a479f869829bfd8150282c590deee6d099bbb6e"}, - {file = "numpy-1.22.2.zip", hash = "sha256:076aee5a3763d41da6bef9565fdf3cb987606f567cd8b104aded2b38b7b47abf"}, -] -openpyxl = [ - {file = "openpyxl-3.0.9-py2.py3-none-any.whl", hash = "sha256:8f3b11bd896a95468a4ab162fc4fcd260d46157155d1f8bfaabb99d88cfcf79f"}, - {file = "openpyxl-3.0.9.tar.gz", hash = "sha256:40f568b9829bf9e446acfffce30250ac1fa39035124d55fc024025c41481c90f"}, -] -orderedmultidict = [ - {file = "orderedmultidict-1.0.1-py2.py3-none-any.whl", hash = "sha256:43c839a17ee3cdd62234c47deca1a8508a3f2ca1d0678a3bf791c87cf84adbf3"}, - {file = "orderedmultidict-1.0.1.tar.gz", hash = "sha256:04070bbb5e87291cc9bfa51df413677faf2141c73c61d2a5f7b26bea3cd882ad"}, -] -packaging = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, -] -pandas = [ - {file = "pandas-1.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:be67c782c4f1b1f24c2f16a157e12c2693fd510f8df18e3287c77f33d124ed07"}, - {file = "pandas-1.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5a206afa84ed20e07603f50d22b5f0db3fb556486d8c2462d8bc364831a4b417"}, - {file = "pandas-1.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0010771bd9223f7afe5f051eb47c4a49534345dfa144f2f5470b27189a4dd3b5"}, - {file = "pandas-1.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3228198333dd13c90b6434ddf61aa6d57deaca98cf7b654f4ad68a2db84f8cfe"}, - {file = "pandas-1.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b79af3a69e5175c6fa7b4e046b21a646c8b74e92c6581a9d825687d92071b51"}, - {file = "pandas-1.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:5586cc95692564b441f4747c47c8a9746792e87b40a4680a2feb7794defb1ce3"}, - {file = "pandas-1.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:061609334a8182ab500a90fe66d46f6f387de62d3a9cb9aa7e62e3146c712167"}, - {file = "pandas-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b8134651258bce418cb79c71adeff0a44090c98d955f6953168ba16cc285d9f7"}, - {file = "pandas-1.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:df82739e00bb6daf4bba4479a40f38c718b598a84654cbd8bb498fd6b0aa8c16"}, - {file = "pandas-1.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:385c52e85aaa8ea6a4c600a9b2821181a51f8be0aee3af6f2dcb41dafc4fc1d0"}, - {file = "pandas-1.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:295872bf1a09758aba199992c3ecde455f01caf32266d50abc1a073e828a7b9d"}, - {file = "pandas-1.4.2-cp38-cp38-win32.whl", hash = "sha256:95c1e422ced0199cf4a34385ff124b69412c4bc912011ce895582bee620dfcaa"}, - {file = "pandas-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:5c54ea4ef3823108cd4ec7fb27ccba4c3a775e0f83e39c5e17f5094cb17748bc"}, - {file = "pandas-1.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c072c7f06b9242c855ed8021ff970c0e8f8b10b35e2640c657d2a541c5950f59"}, - {file = "pandas-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f549097993744ff8c41b5e8f2f0d3cbfaabe89b4ae32c8c08ead6cc535b80139"}, - {file = "pandas-1.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ff08a14ef21d94cdf18eef7c569d66f2e24e0bc89350bcd7d243dd804e3b5eb2"}, - {file = "pandas-1.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c5bf555b6b0075294b73965adaafb39cf71c312e38c5935c93d78f41c19828a"}, - {file = "pandas-1.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51649ef604a945f781105a6d2ecf88db7da0f4868ac5d45c51cb66081c4d9c73"}, - {file = "pandas-1.4.2-cp39-cp39-win32.whl", hash = "sha256:d0d4f13e4be7ce89d7057a786023c461dd9370040bdb5efa0a7fe76b556867a0"}, - {file = "pandas-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:09d8be7dd9e1c4c98224c4dfe8abd60d145d934e9fc1f5f411266308ae683e6a"}, - {file = "pandas-1.4.2.tar.gz", hash = "sha256:92bc1fc585f1463ca827b45535957815b7deb218c549b7c18402c322c7549a12"}, -] -pathspec = [ - {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, - {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, -] -platformdirs = [ - {file = "platformdirs-2.5.0-py3-none-any.whl", hash = "sha256:30671902352e97b1eafd74ade8e4a694782bd3471685e78c32d0fdfd3aa7e7bb"}, - {file = "platformdirs-2.5.0.tar.gz", hash = "sha256:8ec11dfba28ecc0715eb5fb0147a87b1bf325f349f3da9aab2cd6b50b96b692b"}, -] -prompt-toolkit = [ - {file = "prompt_toolkit-3.0.28-py3-none-any.whl", hash = "sha256:30129d870dcb0b3b6a53efdc9d0a83ea96162ffd28ffe077e94215b233dc670c"}, - {file = "prompt_toolkit-3.0.28.tar.gz", hash = "sha256:9f1cd16b1e86c2968f2519d7fb31dd9d669916f515612c269d14e9ed52b51650"}, -] -protobuf = [ - {file = "protobuf-3.19.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f51d5a9f137f7a2cec2d326a74b6e3fc79d635d69ffe1b036d39fc7d75430d37"}, - {file = "protobuf-3.19.4-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:09297b7972da685ce269ec52af761743714996b4381c085205914c41fcab59fb"}, - {file = "protobuf-3.19.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:072fbc78d705d3edc7ccac58a62c4c8e0cec856987da7df8aca86e647be4e35c"}, - {file = "protobuf-3.19.4-cp310-cp310-win32.whl", hash = "sha256:7bb03bc2873a2842e5ebb4801f5c7ff1bfbdf426f85d0172f7644fcda0671ae0"}, - {file = "protobuf-3.19.4-cp310-cp310-win_amd64.whl", hash = "sha256:f358aa33e03b7a84e0d91270a4d4d8f5df6921abe99a377828839e8ed0c04e07"}, - {file = "protobuf-3.19.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1c91ef4110fdd2c590effb5dca8fdbdcb3bf563eece99287019c4204f53d81a4"}, - {file = "protobuf-3.19.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c438268eebb8cf039552897d78f402d734a404f1360592fef55297285f7f953f"}, - {file = "protobuf-3.19.4-cp36-cp36m-win32.whl", hash = "sha256:835a9c949dc193953c319603b2961c5c8f4327957fe23d914ca80d982665e8ee"}, - {file = "protobuf-3.19.4-cp36-cp36m-win_amd64.whl", hash = "sha256:4276cdec4447bd5015453e41bdc0c0c1234eda08420b7c9a18b8d647add51e4b"}, - {file = "protobuf-3.19.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6cbc312be5e71869d9d5ea25147cdf652a6781cf4d906497ca7690b7b9b5df13"}, - {file = "protobuf-3.19.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:54a1473077f3b616779ce31f477351a45b4fef8c9fd7892d6d87e287a38df368"}, - {file = "protobuf-3.19.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:435bb78b37fc386f9275a7035fe4fb1364484e38980d0dd91bc834a02c5ec909"}, - {file = "protobuf-3.19.4-cp37-cp37m-win32.whl", hash = "sha256:16f519de1313f1b7139ad70772e7db515b1420d208cb16c6d7858ea989fc64a9"}, - {file = "protobuf-3.19.4-cp37-cp37m-win_amd64.whl", hash = "sha256:cdc076c03381f5c1d9bb1abdcc5503d9ca8b53cf0a9d31a9f6754ec9e6c8af0f"}, - {file = "protobuf-3.19.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:69da7d39e39942bd52848438462674c463e23963a1fdaa84d88df7fbd7e749b2"}, - {file = "protobuf-3.19.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:48ed3877fa43e22bcacc852ca76d4775741f9709dd9575881a373bd3e85e54b2"}, - {file = "protobuf-3.19.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd95d1dfb9c4f4563e6093a9aa19d9c186bf98fa54da5252531cc0d3a07977e7"}, - {file = "protobuf-3.19.4-cp38-cp38-win32.whl", hash = "sha256:b38057450a0c566cbd04890a40edf916db890f2818e8682221611d78dc32ae26"}, - {file = "protobuf-3.19.4-cp38-cp38-win_amd64.whl", hash = "sha256:7ca7da9c339ca8890d66958f5462beabd611eca6c958691a8fe6eccbd1eb0c6e"}, - {file = "protobuf-3.19.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:36cecbabbda242915529b8ff364f2263cd4de7c46bbe361418b5ed859677ba58"}, - {file = "protobuf-3.19.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c1068287025f8ea025103e37d62ffd63fec8e9e636246b89c341aeda8a67c934"}, - {file = "protobuf-3.19.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96bd766831596d6014ca88d86dc8fe0fb2e428c0b02432fd9db3943202bf8c5e"}, - {file = "protobuf-3.19.4-cp39-cp39-win32.whl", hash = "sha256:84123274d982b9e248a143dadd1b9815049f4477dc783bf84efe6250eb4b836a"}, - {file = "protobuf-3.19.4-cp39-cp39-win_amd64.whl", hash = "sha256:3112b58aac3bac9c8be2b60a9daf6b558ca3f7681c130dcdd788ade7c9ffbdca"}, - {file = "protobuf-3.19.4-py2.py3-none-any.whl", hash = "sha256:8961c3a78ebfcd000920c9060a262f082f29838682b1f7201889300c1fbe0616"}, - {file = "protobuf-3.19.4.tar.gz", hash = "sha256:9df0c10adf3e83015ced42a9a7bd64e13d06c4cf45c340d2c63020ea04499d0a"}, -] -psutil = [ - {file = "psutil-5.9.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:55ce319452e3d139e25d6c3f85a1acf12d1607ddedea5e35fb47a552c051161b"}, - {file = "psutil-5.9.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:7336292a13a80eb93c21f36bde4328aa748a04b68c13d01dfddd67fc13fd0618"}, - {file = "psutil-5.9.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:cb8d10461c1ceee0c25a64f2dd54872b70b89c26419e147a05a10b753ad36ec2"}, - {file = "psutil-5.9.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:7641300de73e4909e5d148e90cc3142fb890079e1525a840cf0dfd39195239fd"}, - {file = "psutil-5.9.0-cp27-none-win32.whl", hash = "sha256:ea42d747c5f71b5ccaa6897b216a7dadb9f52c72a0fe2b872ef7d3e1eacf3ba3"}, - {file = "psutil-5.9.0-cp27-none-win_amd64.whl", hash = "sha256:ef216cc9feb60634bda2f341a9559ac594e2eeaadd0ba187a4c2eb5b5d40b91c"}, - {file = "psutil-5.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90a58b9fcae2dbfe4ba852b57bd4a1dded6b990a33d6428c7614b7d48eccb492"}, - {file = "psutil-5.9.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff0d41f8b3e9ebb6b6110057e40019a432e96aae2008951121ba4e56040b84f3"}, - {file = "psutil-5.9.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:742c34fff804f34f62659279ed5c5b723bb0195e9d7bd9907591de9f8f6558e2"}, - {file = "psutil-5.9.0-cp310-cp310-win32.whl", hash = "sha256:8293942e4ce0c5689821f65ce6522ce4786d02af57f13c0195b40e1edb1db61d"}, - {file = "psutil-5.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:9b51917c1af3fa35a3f2dabd7ba96a2a4f19df3dec911da73875e1edaf22a40b"}, - {file = "psutil-5.9.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e9805fed4f2a81de98ae5fe38b75a74c6e6ad2df8a5c479594c7629a1fe35f56"}, - {file = "psutil-5.9.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c51f1af02334e4b516ec221ee26b8fdf105032418ca5a5ab9737e8c87dafe203"}, - {file = "psutil-5.9.0-cp36-cp36m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32acf55cb9a8cbfb29167cd005951df81b567099295291bcfd1027365b36591d"}, - {file = "psutil-5.9.0-cp36-cp36m-win32.whl", hash = "sha256:e5c783d0b1ad6ca8a5d3e7b680468c9c926b804be83a3a8e95141b05c39c9f64"}, - {file = "psutil-5.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:d62a2796e08dd024b8179bd441cb714e0f81226c352c802fca0fd3f89eeacd94"}, - {file = "psutil-5.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3d00a664e31921009a84367266b35ba0aac04a2a6cad09c550a89041034d19a0"}, - {file = "psutil-5.9.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7779be4025c540d1d65a2de3f30caeacc49ae7a2152108adeaf42c7534a115ce"}, - {file = "psutil-5.9.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:072664401ae6e7c1bfb878c65d7282d4b4391f1bc9a56d5e03b5a490403271b5"}, - {file = "psutil-5.9.0-cp37-cp37m-win32.whl", hash = "sha256:df2c8bd48fb83a8408c8390b143c6a6fa10cb1a674ca664954de193fdcab36a9"}, - {file = "psutil-5.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1d7b433519b9a38192dfda962dd8f44446668c009833e1429a52424624f408b4"}, - {file = "psutil-5.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c3400cae15bdb449d518545cbd5b649117de54e3596ded84aacabfbb3297ead2"}, - {file = "psutil-5.9.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2237f35c4bbae932ee98902a08050a27821f8f6dfa880a47195e5993af4702d"}, - {file = "psutil-5.9.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1070a9b287846a21a5d572d6dddd369517510b68710fca56b0e9e02fd24bed9a"}, - {file = "psutil-5.9.0-cp38-cp38-win32.whl", hash = "sha256:76cebf84aac1d6da5b63df11fe0d377b46b7b500d892284068bacccf12f20666"}, - {file = "psutil-5.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:3151a58f0fbd8942ba94f7c31c7e6b310d2989f4da74fcbf28b934374e9bf841"}, - {file = "psutil-5.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:539e429da49c5d27d5a58e3563886057f8fc3868a5547b4f1876d9c0f007bccf"}, - {file = "psutil-5.9.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58c7d923dc209225600aec73aa2c4ae8ea33b1ab31bc11ef8a5933b027476f07"}, - {file = "psutil-5.9.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3611e87eea393f779a35b192b46a164b1d01167c9d323dda9b1e527ea69d697d"}, - {file = "psutil-5.9.0-cp39-cp39-win32.whl", hash = "sha256:4e2fb92e3aeae3ec3b7b66c528981fd327fb93fd906a77215200404444ec1845"}, - {file = "psutil-5.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:7d190ee2eaef7831163f254dc58f6d2e2a22e27382b936aab51c835fc080c3d3"}, - {file = "psutil-5.9.0.tar.gz", hash = "sha256:869842dbd66bb80c3217158e629d6fceaecc3a3166d3d1faee515b05dd26ca25"}, -] -pyasn1 = [ - {file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"}, - {file = "pyasn1-0.4.8-py2.5.egg", hash = "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf"}, - {file = "pyasn1-0.4.8-py2.6.egg", hash = "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00"}, - {file = "pyasn1-0.4.8-py2.7.egg", hash = "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8"}, - {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, - {file = "pyasn1-0.4.8-py3.1.egg", hash = "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86"}, - {file = "pyasn1-0.4.8-py3.2.egg", hash = "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7"}, - {file = "pyasn1-0.4.8-py3.3.egg", hash = "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576"}, - {file = "pyasn1-0.4.8-py3.4.egg", hash = "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12"}, - {file = "pyasn1-0.4.8-py3.5.egg", hash = "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2"}, - {file = "pyasn1-0.4.8-py3.6.egg", hash = "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359"}, - {file = "pyasn1-0.4.8-py3.7.egg", hash = "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776"}, - {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, -] -pyasn1-modules = [ - {file = "pyasn1-modules-0.2.8.tar.gz", hash = "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e"}, - {file = "pyasn1_modules-0.2.8-py2.4.egg", hash = "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199"}, - {file = "pyasn1_modules-0.2.8-py2.5.egg", hash = "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405"}, - {file = "pyasn1_modules-0.2.8-py2.6.egg", hash = "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb"}, - {file = "pyasn1_modules-0.2.8-py2.7.egg", hash = "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8"}, - {file = "pyasn1_modules-0.2.8-py2.py3-none-any.whl", hash = "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"}, - {file = "pyasn1_modules-0.2.8-py3.1.egg", hash = "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d"}, - {file = "pyasn1_modules-0.2.8-py3.2.egg", hash = "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45"}, - {file = "pyasn1_modules-0.2.8-py3.3.egg", hash = "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4"}, - {file = "pyasn1_modules-0.2.8-py3.4.egg", hash = "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811"}, - {file = "pyasn1_modules-0.2.8-py3.5.egg", hash = "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed"}, - {file = "pyasn1_modules-0.2.8-py3.6.egg", hash = "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0"}, - {file = "pyasn1_modules-0.2.8-py3.7.egg", hash = "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd"}, -] -pycodestyle = [ - {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, - {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, -] -pydantic = [ - {file = "pydantic-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cb23bcc093697cdea2708baae4f9ba0e972960a835af22560f6ae4e7e47d33f5"}, - {file = "pydantic-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1d5278bd9f0eee04a44c712982343103bba63507480bfd2fc2790fa70cd64cf4"}, - {file = "pydantic-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab624700dc145aa809e6f3ec93fb8e7d0f99d9023b713f6a953637429b437d37"}, - {file = "pydantic-1.9.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c8d7da6f1c1049eefb718d43d99ad73100c958a5367d30b9321b092771e96c25"}, - {file = "pydantic-1.9.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3c3b035103bd4e2e4a28da9da7ef2fa47b00ee4a9cf4f1a735214c1bcd05e0f6"}, - {file = "pydantic-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3011b975c973819883842c5ab925a4e4298dffccf7782c55ec3580ed17dc464c"}, - {file = "pydantic-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:086254884d10d3ba16da0588604ffdc5aab3f7f09557b998373e885c690dd398"}, - {file = "pydantic-1.9.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0fe476769acaa7fcddd17cadd172b156b53546ec3614a4d880e5d29ea5fbce65"}, - {file = "pydantic-1.9.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8e9dcf1ac499679aceedac7e7ca6d8641f0193c591a2d090282aaf8e9445a46"}, - {file = "pydantic-1.9.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1e4c28f30e767fd07f2ddc6f74f41f034d1dd6bc526cd59e63a82fe8bb9ef4c"}, - {file = "pydantic-1.9.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:c86229333cabaaa8c51cf971496f10318c4734cf7b641f08af0a6fbf17ca3054"}, - {file = "pydantic-1.9.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:c0727bda6e38144d464daec31dff936a82917f431d9c39c39c60a26567eae3ed"}, - {file = "pydantic-1.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:dee5ef83a76ac31ab0c78c10bd7d5437bfdb6358c95b91f1ba7ff7b76f9996a1"}, - {file = "pydantic-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9c9bdb3af48e242838f9f6e6127de9be7063aad17b32215ccc36a09c5cf1070"}, - {file = "pydantic-1.9.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ee7e3209db1e468341ef41fe263eb655f67f5c5a76c924044314e139a1103a2"}, - {file = "pydantic-1.9.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b6037175234850ffd094ca77bf60fb54b08b5b22bc85865331dd3bda7a02fa1"}, - {file = "pydantic-1.9.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b2571db88c636d862b35090ccf92bf24004393f85c8870a37f42d9f23d13e032"}, - {file = "pydantic-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8b5ac0f1c83d31b324e57a273da59197c83d1bb18171e512908fe5dc7278a1d6"}, - {file = "pydantic-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:bbbc94d0c94dd80b3340fc4f04fd4d701f4b038ebad72c39693c794fd3bc2d9d"}, - {file = "pydantic-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e0896200b6a40197405af18828da49f067c2fa1f821491bc8f5bde241ef3f7d7"}, - {file = "pydantic-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bdfdadb5994b44bd5579cfa7c9b0e1b0e540c952d56f627eb227851cda9db77"}, - {file = "pydantic-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:574936363cd4b9eed8acdd6b80d0143162f2eb654d96cb3a8ee91d3e64bf4cf9"}, - {file = "pydantic-1.9.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c556695b699f648c58373b542534308922c46a1cda06ea47bc9ca45ef5b39ae6"}, - {file = "pydantic-1.9.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f947352c3434e8b937e3aa8f96f47bdfe6d92779e44bb3f41e4c213ba6a32145"}, - {file = "pydantic-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5e48ef4a8b8c066c4a31409d91d7ca372a774d0212da2787c0d32f8045b1e034"}, - {file = "pydantic-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:96f240bce182ca7fe045c76bcebfa0b0534a1bf402ed05914a6f1dadff91877f"}, - {file = "pydantic-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:815ddebb2792efd4bba5488bc8fde09c29e8ca3227d27cf1c6990fc830fd292b"}, - {file = "pydantic-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c5b77947b9e85a54848343928b597b4f74fc364b70926b3c4441ff52620640c"}, - {file = "pydantic-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c68c3bc88dbda2a6805e9a142ce84782d3930f8fdd9655430d8576315ad97ce"}, - {file = "pydantic-1.9.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a79330f8571faf71bf93667d3ee054609816f10a259a109a0738dac983b23c3"}, - {file = "pydantic-1.9.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f5a64b64ddf4c99fe201ac2724daada8595ada0d102ab96d019c1555c2d6441d"}, - {file = "pydantic-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a733965f1a2b4090a5238d40d983dcd78f3ecea221c7af1497b845a9709c1721"}, - {file = "pydantic-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cc6a4cb8a118ffec2ca5fcb47afbacb4f16d0ab8b7350ddea5e8ef7bcc53a16"}, - {file = "pydantic-1.9.0-py3-none-any.whl", hash = "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3"}, - {file = "pydantic-1.9.0.tar.gz", hash = "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a"}, -] -pyexcel = [ - {file = "pyexcel-0.7.0-py2.py3-none-any.whl", hash = "sha256:ddc6904512bfa2ecda509fb3b58229bb30db14498632fd9e7a5ba7bbfb02ed1b"}, - {file = "pyexcel-0.7.0.tar.gz", hash = "sha256:fbf0eee5d93b96cef6f19a9f00703f22c0a64f19728d91b95428009a52129709"}, -] -pyexcel-io = [ - {file = "pyexcel-io-0.6.6.tar.gz", hash = "sha256:f6084bf1afa5fbf4c61cf7df44370fa513821af188b02e3e19b5efb66d8a969f"}, - {file = "pyexcel_io-0.6.6-py2.py3-none-any.whl", hash = "sha256:19ff1d599a8a6c0982e4181ef86aa50e1f8d231410fa7e0e204d62e37551c1d6"}, -] -pyexcel-xlsx = [ - {file = "pyexcel-xlsx-0.6.0.tar.gz", hash = "sha256:55754f764252461aca6871db203f4bd1370ec877828e305e6be1de5f9aa6a79d"}, - {file = "pyexcel_xlsx-0.6.0-py2.py3-none-any.whl", hash = "sha256:16530f96a77c97ebcba7941517d2756ac52d3ce2903d81eecd7f300778d5242a"}, -] -pyflakes = [ - {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, - {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, -] -pyparsing = [ - {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, - {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, -] -pyproject-flake8 = [ - {file = "pyproject-flake8-0.0.1a2.tar.gz", hash = "sha256:bdeca37f78ecd34bd64a49d3657d53d099f5445831071a31c46e1fe20cd61461"}, - {file = "pyproject_flake8-0.0.1a2-py2.py3-none-any.whl", hash = "sha256:e61ed1dc088e9f9f8a7170967ac4ec135acfef3a59ab9738c7b58cc11f294a7e"}, -] -python-dateutil = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, -] -python-dotenv = [ - {file = "python-dotenv-0.19.2.tar.gz", hash = "sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f"}, - {file = "python_dotenv-0.19.2-py2.py3-none-any.whl", hash = "sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3"}, -] -pytz = [ - {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, - {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, -] -requests = [ - {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, - {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, -] -rsa = [ - {file = "rsa-4.8-py3-none-any.whl", hash = "sha256:95c5d300c4e879ee69708c428ba566c59478fd653cc3a22243eeb8ed846950bb"}, - {file = "rsa-4.8.tar.gz", hash = "sha256:5c6bd9dc7a543b7fe4304a631f8a8a3b674e2bbfc49c2ae96200cdbe55df6b17"}, -] -"ruamel.yaml" = [ - {file = "ruamel.yaml-0.17.21-py3-none-any.whl", hash = "sha256:742b35d3d665023981bd6d16b3d24248ce5df75fdb4e2924e93a05c1f8b61ca7"}, - {file = "ruamel.yaml-0.17.21.tar.gz", hash = "sha256:8b7ce697a2f212752a35c1ac414471dc16c424c9573be4926b56ff3f5d23b7af"}, -] -"ruamel.yaml.clib" = [ - {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6e7be2c5bcb297f5b82fee9c665eb2eb7001d1050deaba8471842979293a80b0"}, - {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:221eca6f35076c6ae472a531afa1c223b9c29377e62936f61bc8e6e8bdc5f9e7"}, - {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-win32.whl", hash = "sha256:1070ba9dd7f9370d0513d649420c3b362ac2d687fe78c6e888f5b12bf8bc7bee"}, - {file = "ruamel.yaml.clib-0.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:77df077d32921ad46f34816a9a16e6356d8100374579bc35e15bab5d4e9377de"}, - {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:cfdb9389d888c5b74af297e51ce357b800dd844898af9d4a547ffc143fa56751"}, - {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7b2927e92feb51d830f531de4ccb11b320255ee95e791022555971c466af4527"}, - {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-win32.whl", hash = "sha256:ada3f400d9923a190ea8b59c8f60680c4ef8a4b0dfae134d2f2ff68429adfab5"}, - {file = "ruamel.yaml.clib-0.2.6-cp35-cp35m-win_amd64.whl", hash = "sha256:de9c6b8a1ba52919ae919f3ae96abb72b994dd0350226e28f3686cb4f142165c"}, - {file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d67f273097c368265a7b81e152e07fb90ed395df6e552b9fa858c6d2c9f42502"}, - {file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:72a2b8b2ff0a627496aad76f37a652bcef400fd861721744201ef1b45199ab78"}, - {file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-win32.whl", hash = "sha256:9efef4aab5353387b07f6b22ace0867032b900d8e91674b5d8ea9150db5cae94"}, - {file = "ruamel.yaml.clib-0.2.6-cp36-cp36m-win_amd64.whl", hash = "sha256:846fc8336443106fe23f9b6d6b8c14a53d38cef9a375149d61f99d78782ea468"}, - {file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0847201b767447fc33b9c235780d3aa90357d20dd6108b92be544427bea197dd"}, - {file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:78988ed190206672da0f5d50c61afef8f67daa718d614377dcd5e3ed85ab4a99"}, - {file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-win32.whl", hash = "sha256:a49e0161897901d1ac9c4a79984b8410f450565bbad64dbfcbf76152743a0cdb"}, - {file = "ruamel.yaml.clib-0.2.6-cp37-cp37m-win_amd64.whl", hash = "sha256:bf75d28fa071645c529b5474a550a44686821decebdd00e21127ef1fd566eabe"}, - {file = "ruamel.yaml.clib-0.2.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a32f8d81ea0c6173ab1b3da956869114cae53ba1e9f72374032e33ba3118c233"}, - {file = "ruamel.yaml.clib-0.2.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7f7ecb53ae6848f959db6ae93bdff1740e651809780822270eab111500842a84"}, - {file = "ruamel.yaml.clib-0.2.6-cp38-cp38-win32.whl", hash = "sha256:89221ec6d6026f8ae859c09b9718799fea22c0e8da8b766b0b2c9a9ba2db326b"}, - {file = "ruamel.yaml.clib-0.2.6-cp38-cp38-win_amd64.whl", hash = "sha256:31ea73e564a7b5fbbe8188ab8b334393e06d997914a4e184975348f204790277"}, - {file = "ruamel.yaml.clib-0.2.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dc6a613d6c74eef5a14a214d433d06291526145431c3b964f5e16529b1842bed"}, - {file = "ruamel.yaml.clib-0.2.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1866cf2c284a03b9524a5cc00daca56d80057c5ce3cdc86a52020f4c720856f0"}, - {file = "ruamel.yaml.clib-0.2.6-cp39-cp39-win32.whl", hash = "sha256:3fb9575a5acd13031c57a62cc7823e5d2ff8bc3835ba4d94b921b4e6ee664104"}, - {file = "ruamel.yaml.clib-0.2.6-cp39-cp39-win_amd64.whl", hash = "sha256:825d5fccef6da42f3c8eccd4281af399f21c02b32d98e113dbc631ea6a6ecbc7"}, - {file = "ruamel.yaml.clib-0.2.6.tar.gz", hash = "sha256:4ff604ce439abb20794f05613c374759ce10e3595d1867764dd1ae675b85acbd"}, -] -s3transfer = [ - {file = "s3transfer-0.5.1-py3-none-any.whl", hash = "sha256:25c140f5c66aa79e1ac60be50dcd45ddc59e83895f062a3aab263b870102911f"}, - {file = "s3transfer-0.5.1.tar.gz", hash = "sha256:69d264d3e760e569b78aaa0f22c97e955891cd22e32b10c51f784eeda4d9d10a"}, -] -scikit-learn = [ - {file = "scikit-learn-1.0.2.tar.gz", hash = "sha256:b5870959a5484b614f26d31ca4c17524b1b0317522199dc985c3b4256e030767"}, - {file = "scikit_learn-1.0.2-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:da3c84694ff693b5b3194d8752ccf935a665b8b5edc33a283122f4273ca3e687"}, - {file = "scikit_learn-1.0.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:75307d9ea39236cad7eea87143155eea24d48f93f3a2f9389c817f7019f00705"}, - {file = "scikit_learn-1.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f14517e174bd7332f1cca2c959e704696a5e0ba246eb8763e6c24876d8710049"}, - {file = "scikit_learn-1.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9aac97e57c196206179f674f09bc6bffcd0284e2ba95b7fe0b402ac3f986023"}, - {file = "scikit_learn-1.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:d93d4c28370aea8a7cbf6015e8a669cd5d69f856cc2aa44e7a590fb805bb5583"}, - {file = "scikit_learn-1.0.2-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:85260fb430b795d806251dd3bb05e6f48cdc777ac31f2bcf2bc8bbed3270a8f5"}, - {file = "scikit_learn-1.0.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a053a6a527c87c5c4fa7bf1ab2556fa16d8345cf99b6c5a19030a4a7cd8fd2c0"}, - {file = "scikit_learn-1.0.2-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:245c9b5a67445f6f044411e16a93a554edc1efdcce94d3fc0bc6a4b9ac30b752"}, - {file = "scikit_learn-1.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:158faf30684c92a78e12da19c73feff9641a928a8024b4fa5ec11d583f3d8a87"}, - {file = "scikit_learn-1.0.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:08ef968f6b72033c16c479c966bf37ccd49b06ea91b765e1cc27afefe723920b"}, - {file = "scikit_learn-1.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16455ace947d8d9e5391435c2977178d0ff03a261571e67f627c8fee0f9d431a"}, - {file = "scikit_learn-1.0.2-cp37-cp37m-win32.whl", hash = "sha256:2f3b453e0b149898577e301d27e098dfe1a36943f7bb0ad704d1e548efc3b448"}, - {file = "scikit_learn-1.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:46f431ec59dead665e1370314dbebc99ead05e1c0a9df42f22d6a0e00044820f"}, - {file = "scikit_learn-1.0.2-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:ff3fa8ea0e09e38677762afc6e14cad77b5e125b0ea70c9bba1992f02c93b028"}, - {file = "scikit_learn-1.0.2-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:9369b030e155f8188743eb4893ac17a27f81d28a884af460870c7c072f114243"}, - {file = "scikit_learn-1.0.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7d6b2475f1c23a698b48515217eb26b45a6598c7b1840ba23b3c5acece658dbb"}, - {file = "scikit_learn-1.0.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:285db0352e635b9e3392b0b426bc48c3b485512d3b4ac3c7a44ec2a2ba061e66"}, - {file = "scikit_learn-1.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cb33fe1dc6f73dc19e67b264dbb5dde2a0539b986435fdd78ed978c14654830"}, - {file = "scikit_learn-1.0.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1391d1a6e2268485a63c3073111fe3ba6ec5145fc957481cfd0652be571226d"}, - {file = "scikit_learn-1.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc3744dabc56b50bec73624aeca02e0def06b03cb287de26836e730659c5d29c"}, - {file = "scikit_learn-1.0.2-cp38-cp38-win32.whl", hash = "sha256:a999c9f02ff9570c783069f1074f06fe7386ec65b84c983db5aeb8144356a355"}, - {file = "scikit_learn-1.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:7626a34eabbf370a638f32d1a3ad50526844ba58d63e3ab81ba91e2a7c6d037e"}, - {file = "scikit_learn-1.0.2-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:a90b60048f9ffdd962d2ad2fb16367a87ac34d76e02550968719eb7b5716fd10"}, - {file = "scikit_learn-1.0.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:7a93c1292799620df90348800d5ac06f3794c1316ca247525fa31169f6d25855"}, - {file = "scikit_learn-1.0.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:eabceab574f471de0b0eb3f2ecf2eee9f10b3106570481d007ed1c84ebf6d6a1"}, - {file = "scikit_learn-1.0.2-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:55f2f3a8414e14fbee03782f9fe16cca0f141d639d2b1c1a36779fa069e1db57"}, - {file = "scikit_learn-1.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80095a1e4b93bd33261ef03b9bc86d6db649f988ea4dbcf7110d0cded8d7213d"}, - {file = "scikit_learn-1.0.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa38a1b9b38ae1fad2863eff5e0d69608567453fdfc850c992e6e47eb764e846"}, - {file = "scikit_learn-1.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff746a69ff2ef25f62b36338c615dd15954ddc3ab8e73530237dd73235e76d62"}, - {file = "scikit_learn-1.0.2-cp39-cp39-win32.whl", hash = "sha256:e174242caecb11e4abf169342641778f68e1bfaba80cd18acd6bc84286b9a534"}, - {file = "scikit_learn-1.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:b54a62c6e318ddbfa7d22c383466d38d2ee770ebdb5ddb668d56a099f6eaf75f"}, -] -scipy = [ - {file = "scipy-1.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a15a1f3fc0abff33e792d6049161b7795909b40b97c6cc2934ed54384017ab76"}, - {file = "scipy-1.6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e79570979ccdc3d165456dd62041d9556fb9733b86b4b6d818af7a0afc15f092"}, - {file = "scipy-1.6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a423533c55fec61456dedee7b6ee7dce0bb6bfa395424ea374d25afa262be261"}, - {file = "scipy-1.6.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:33d6b7df40d197bdd3049d64e8e680227151673465e5d85723b3b8f6b15a6ced"}, - {file = "scipy-1.6.1-cp37-cp37m-win32.whl", hash = "sha256:6725e3fbb47da428794f243864f2297462e9ee448297c93ed1dcbc44335feb78"}, - {file = "scipy-1.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:5fa9c6530b1661f1370bcd332a1e62ca7881785cc0f80c0d559b636567fab63c"}, - {file = "scipy-1.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd50daf727f7c195e26f27467c85ce653d41df4358a25b32434a50d8870fc519"}, - {file = "scipy-1.6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:f46dd15335e8a320b0fb4685f58b7471702234cba8bb3442b69a3e1dc329c345"}, - {file = "scipy-1.6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:0e5b0ccf63155d90da576edd2768b66fb276446c371b73841e3503be1d63fb5d"}, - {file = "scipy-1.6.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2481efbb3740977e3c831edfd0bd9867be26387cacf24eb5e366a6a374d3d00d"}, - {file = "scipy-1.6.1-cp38-cp38-win32.whl", hash = "sha256:68cb4c424112cd4be886b4d979c5497fba190714085f46b8ae67a5e4416c32b4"}, - {file = "scipy-1.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:5f331eeed0297232d2e6eea51b54e8278ed8bb10b099f69c44e2558c090d06bf"}, - {file = "scipy-1.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0c8a51d33556bf70367452d4d601d1742c0e806cd0194785914daf19775f0e67"}, - {file = "scipy-1.6.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:83bf7c16245c15bc58ee76c5418e46ea1811edcc2e2b03041b804e46084ab627"}, - {file = "scipy-1.6.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:794e768cc5f779736593046c9714e0f3a5940bc6dcc1dba885ad64cbfb28e9f0"}, - {file = "scipy-1.6.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5da5471aed911fe7e52b86bf9ea32fb55ae93e2f0fac66c32e58897cfb02fa07"}, - {file = "scipy-1.6.1-cp39-cp39-win32.whl", hash = "sha256:8e403a337749ed40af60e537cc4d4c03febddcc56cd26e774c9b1b600a70d3e4"}, - {file = "scipy-1.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:a5193a098ae9f29af283dcf0041f762601faf2e595c0db1da929875b7570353f"}, - {file = "scipy-1.6.1.tar.gz", hash = "sha256:c4fceb864890b6168e79b0e714c585dbe2fd4222768ee90bc1aa0f8218691b11"}, -] -seqeval = [ - {file = "seqeval-1.2.2.tar.gz", hash = "sha256:f28e97c3ab96d6fcd32b648f6438ff2e09cfba87f05939da9b3970713ec56e6f"}, -] -shortuuid = [ - {file = "shortuuid-1.0.8-py3-none-any.whl", hash = "sha256:44a7a86bcf24dbaba2e626cf80c779926b7c3a0d31a3a013e0d3cd1077707d23"}, - {file = "shortuuid-1.0.8.tar.gz", hash = "sha256:9435e87e5a64f3b92f7110c81f989a3b7bdb9358e22d2359829167da476cfc23"}, -] -six = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] -sqlalchemy = [ - {file = "SQLAlchemy-1.4.31-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c3abc34fed19fdeaead0ced8cf56dd121f08198008c033596aa6aae7cc58f59f"}, - {file = "SQLAlchemy-1.4.31-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:8d0949b11681380b4a50ac3cd075e4816afe9fa4a8c8ae006c1ca26f0fa40ad8"}, - {file = "SQLAlchemy-1.4.31-cp27-cp27m-win32.whl", hash = "sha256:f3b7ec97e68b68cb1f9ddb82eda17b418f19a034fa8380a0ac04e8fe01532875"}, - {file = "SQLAlchemy-1.4.31-cp27-cp27m-win_amd64.whl", hash = "sha256:81f2dd355b57770fdf292b54f3e0a9823ec27a543f947fa2eb4ec0df44f35f0d"}, - {file = "SQLAlchemy-1.4.31-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4ad31cec8b49fd718470328ad9711f4dc703507d434fd45461096da0a7135ee0"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:05fa14f279d43df68964ad066f653193187909950aa0163320b728edfc400167"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dccff41478050e823271642837b904d5f9bda3f5cf7d371ce163f00a694118d6"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57205844f246bab9b666a32f59b046add8995c665d9ecb2b7b837b087df90639"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea8210090a816d48a4291a47462bac750e3bc5c2442e6d64f7b8137a7c3f9ac5"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-win32.whl", hash = "sha256:2e216c13ecc7fcdcbb86bb3225425b3ed338e43a8810c7089ddb472676124b9b"}, - {file = "SQLAlchemy-1.4.31-cp310-cp310-win_amd64.whl", hash = "sha256:e3a86b59b6227ef72ffc10d4b23f0fe994bef64d4667eab4fb8cd43de4223bec"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:2fd4d3ca64c41dae31228b80556ab55b6489275fb204827f6560b65f95692cf3"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f22c040d196f841168b1456e77c30a18a3dc16b336ddbc5a24ce01ab4e95ae0"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c0c7171aa5a57e522a04a31b84798b6c926234cb559c0939840c3235cf068813"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d046a9aeba9bc53e88a41e58beb72b6205abb9a20f6c136161adf9128e589db5"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-win32.whl", hash = "sha256:d86132922531f0dc5a4f424c7580a472a924dd737602638e704841c9cb24aea2"}, - {file = "SQLAlchemy-1.4.31-cp36-cp36m-win_amd64.whl", hash = "sha256:ca68c52e3cae491ace2bf39b35fef4ce26c192fd70b4cd90f040d419f70893b5"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:cf2cd387409b12d0a8b801610d6336ee7d24043b6dd965950eaec09b73e7262f"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb4b15fb1f0aafa65cbdc62d3c2078bea1ceecbfccc9a1f23a2113c9ac1191fa"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c317ddd7c586af350a6aef22b891e84b16bff1a27886ed5b30f15c1ed59caeaa"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c7ed6c69debaf6198fadb1c16ae1253a29a7670bbf0646f92582eb465a0b999"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-win32.whl", hash = "sha256:6a01ec49ca54ce03bc14e10de55dfc64187a2194b3b0e5ac0fdbe9b24767e79e"}, - {file = "SQLAlchemy-1.4.31-cp37-cp37m-win_amd64.whl", hash = "sha256:330eb45395874cc7787214fdd4489e2afb931bc49e0a7a8f9cd56d6e9c5b1639"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:5e9c7b3567edbc2183607f7d9f3e7e89355b8f8984eec4d2cd1e1513c8f7b43f"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de85c26a5a1c72e695ab0454e92f60213b4459b8d7c502e0be7a6369690eeb1a"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:975f5c0793892c634c4920057da0de3a48bbbbd0a5c86f5fcf2f2fedf41b76da"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5c20c8415173b119762b6110af64448adccd4d11f273fb9f718a9865b88a99c"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-win32.whl", hash = "sha256:b35dca159c1c9fa8a5f9005e42133eed82705bf8e243da371a5e5826440e65ca"}, - {file = "SQLAlchemy-1.4.31-cp38-cp38-win_amd64.whl", hash = "sha256:b7b20c88873675903d6438d8b33fba027997193e274b9367421e610d9da76c08"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:85e4c244e1de056d48dae466e9baf9437980c19fcde493e0db1a0a986e6d75b4"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79e73d5ee24196d3057340e356e6254af4d10e1fc22d3207ea8342fc5ffb977"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:15a03261aa1e68f208e71ae3cd845b00063d242cbf8c87348a0c2c0fc6e1f2ac"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ddc5e5ccc0160e7ad190e5c61eb57560f38559e22586955f205e537cda26034"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-win32.whl", hash = "sha256:289465162b1fa1e7a982f8abe59d26a8331211cad4942e8031d2b7db1f75e649"}, - {file = "SQLAlchemy-1.4.31-cp39-cp39-win_amd64.whl", hash = "sha256:9e4fb2895b83993831ba2401b6404de953fdbfa9d7d4fa6a4756294a83bbc94f"}, - {file = "SQLAlchemy-1.4.31.tar.gz", hash = "sha256:582b59d1e5780a447aada22b461e50b404a9dc05768da1d87368ad8190468418"}, -] -sqlparse = [ - {file = "sqlparse-0.4.2-py3-none-any.whl", hash = "sha256:48719e356bb8b42991bdbb1e8b83223757b93789c00910a616a071910ca4a64d"}, - {file = "sqlparse-0.4.2.tar.gz", hash = "sha256:0c00730c74263a94e5a9919ade150dfc3b19c574389985446148402998287dae"}, -] -taskipy = [ - {file = "taskipy-1.10.1-py3-none-any.whl", hash = "sha256:9b38333654da487b6d16de6fa330b7629d1935d1e74819ba4c5f17a1c372d37b"}, - {file = "taskipy-1.10.1.tar.gz", hash = "sha256:6fa0b11c43d103e376063e90be31d87b435aad50fb7dc1c9a2de9b60a85015ed"}, -] -texttable = [ - {file = "texttable-1.6.4-py2.py3-none-any.whl", hash = "sha256:dd2b0eaebb2a9e167d1cefedab4700e5dcbdb076114eed30b58b97ed6b37d6f2"}, - {file = "texttable-1.6.4.tar.gz", hash = "sha256:42ee7b9e15f7b225747c3fa08f43c5d6c83bc899f80ff9bae9319334824076e9"}, -] -threadpoolctl = [ - {file = "threadpoolctl-3.1.0-py3-none-any.whl", hash = "sha256:8b99adda265feb6773280df41eece7b2e6561b772d21ffd52e372f999024907b"}, - {file = "threadpoolctl-3.1.0.tar.gz", hash = "sha256:a335baacfaa4400ae1f0d8e3a58d6674d2f8828e3716bb2802c44955ad391380"}, -] -toml = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] -tomli = [ - {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, - {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, -] -types-chardet = [ - {file = "types-chardet-4.0.3.tar.gz", hash = "sha256:519850a12ab0009f3ec5bdca35ce1c0de4eb4a67a2110aa206386e6219b3ecd8"}, - {file = "types_chardet-4.0.3-py3-none-any.whl", hash = "sha256:8990a86d4c7cfa6c6c5889fc49e456e477851e75b5adb396d42ae106d0ae02ea"}, -] -types-requests = [ - {file = "types-requests-2.27.10.tar.gz", hash = "sha256:5dcb088fcaa778efeee6b7fc46967037e983fbfb9fec02594578bd33fd75e555"}, - {file = "types_requests-2.27.10-py3-none-any.whl", hash = "sha256:6cb4fb0bbcbc585c57eeee6ffe5a47638dc89706b8d290ec89a77213fc5bad1a"}, -] -types-urllib3 = [ - {file = "types-urllib3-1.26.9.tar.gz", hash = "sha256:abd2d4857837482b1834b4817f0587678dcc531dbc9abe4cde4da28cef3f522c"}, - {file = "types_urllib3-1.26.9-py3-none-any.whl", hash = "sha256:4a54f6274ab1c80968115634a55fb9341a699492b95e32104a7c513db9fe02e9"}, -] -types-waitress = [ - {file = "types-waitress-2.0.6.tar.gz", hash = "sha256:fdd57199a5a7b5b3e65973feb137964bd750cdb1af4f7cc7c9d6053342f86ff2"}, - {file = "types_waitress-2.0.6-py3-none-any.whl", hash = "sha256:d7843d13487effb0e0774ec294f42ca63ed9f74a9296b47e4e290ddb21a05292"}, -] -typing-extensions = [ - {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, - {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, -] -tzdata = [ - {file = "tzdata-2021.5-py2.py3-none-any.whl", hash = "sha256:3eee491e22ebfe1e5cfcc97a4137cd70f092ce59144d81f8924a844de05ba8f5"}, - {file = "tzdata-2021.5.tar.gz", hash = "sha256:68dbe41afd01b867894bbdfd54fa03f468cfa4f0086bfb4adcd8de8f24f3ee21"}, -] -unittest-xml-reporting = [ - {file = "unittest-xml-reporting-3.2.0.tar.gz", hash = "sha256:edd8d3170b40c3a81b8cf910f46c6a304ae2847ec01036d02e9c0f9b85762d28"}, - {file = "unittest_xml_reporting-3.2.0-py2.py3-none-any.whl", hash = "sha256:f3d7402e5b3ac72a5ee3149278339db1a8f932ee405f48bcb9c681372f2717d5"}, -] -uritemplate = [ - {file = "uritemplate-4.1.1-py2.py3-none-any.whl", hash = "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e"}, - {file = "uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0"}, -] -urllib3 = [ - {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"}, - {file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"}, -] -vine = [ - {file = "vine-5.0.0-py2.py3-none-any.whl", hash = "sha256:4c9dceab6f76ed92105027c49c823800dd33cacce13bdedc5b914e3514b7fb30"}, - {file = "vine-5.0.0.tar.gz", hash = "sha256:7d3b1624a953da82ef63462013bbd271d3eb75751489f9807598e8f340bd637e"}, -] -waitress = [ - {file = "waitress-2.1.2-py3-none-any.whl", hash = "sha256:7500c9625927c8ec60f54377d590f67b30c8e70ef4b8894214ac6e4cad233d2a"}, - {file = "waitress-2.1.2.tar.gz", hash = "sha256:780a4082c5fbc0fde6a2fcfe5e26e6efc1e8f425730863c04085769781f51eba"}, -] -watchdog = [ - {file = "watchdog-2.1.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9693f35162dc6208d10b10ddf0458cc09ad70c30ba689d9206e02cd836ce28a3"}, - {file = "watchdog-2.1.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:aba5c812f8ee8a3ff3be51887ca2d55fb8e268439ed44110d3846e4229eb0e8b"}, - {file = "watchdog-2.1.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ae38bf8ba6f39d5b83f78661273216e7db5b00f08be7592062cb1fc8b8ba542"}, - {file = "watchdog-2.1.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ad6f1796e37db2223d2a3f302f586f74c72c630b48a9872c1e7ae8e92e0ab669"}, - {file = "watchdog-2.1.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:922a69fa533cb0c793b483becaaa0845f655151e7256ec73630a1b2e9ebcb660"}, - {file = "watchdog-2.1.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b2fcf9402fde2672545b139694284dc3b665fd1be660d73eca6805197ef776a3"}, - {file = "watchdog-2.1.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3386b367e950a11b0568062b70cc026c6f645428a698d33d39e013aaeda4cc04"}, - {file = "watchdog-2.1.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8f1c00aa35f504197561060ca4c21d3cc079ba29cf6dd2fe61024c70160c990b"}, - {file = "watchdog-2.1.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b52b88021b9541a60531142b0a451baca08d28b74a723d0c99b13c8c8d48d604"}, - {file = "watchdog-2.1.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8047da932432aa32c515ec1447ea79ce578d0559362ca3605f8e9568f844e3c6"}, - {file = "watchdog-2.1.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e92c2d33858c8f560671b448205a268096e17870dcf60a9bb3ac7bfbafb7f5f9"}, - {file = "watchdog-2.1.6-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b7d336912853d7b77f9b2c24eeed6a5065d0a0cc0d3b6a5a45ad6d1d05fb8cd8"}, - {file = "watchdog-2.1.6-py3-none-manylinux2014_aarch64.whl", hash = "sha256:cca7741c0fcc765568350cb139e92b7f9f3c9a08c4f32591d18ab0a6ac9e71b6"}, - {file = "watchdog-2.1.6-py3-none-manylinux2014_armv7l.whl", hash = "sha256:25fb5240b195d17de949588628fdf93032ebf163524ef08933db0ea1f99bd685"}, - {file = "watchdog-2.1.6-py3-none-manylinux2014_i686.whl", hash = "sha256:be9be735f827820a06340dff2ddea1fb7234561fa5e6300a62fe7f54d40546a0"}, - {file = "watchdog-2.1.6-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0d19fb2441947b58fbf91336638c2b9f4cc98e05e1045404d7a4cb7cddc7a65"}, - {file = "watchdog-2.1.6-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:3becdb380d8916c873ad512f1701f8a92ce79ec6978ffde92919fd18d41da7fb"}, - {file = "watchdog-2.1.6-py3-none-manylinux2014_s390x.whl", hash = "sha256:ae67501c95606072aafa865b6ed47343ac6484472a2f95490ba151f6347acfc2"}, - {file = "watchdog-2.1.6-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e0f30db709c939cabf64a6dc5babb276e6d823fd84464ab916f9b9ba5623ca15"}, - {file = "watchdog-2.1.6-py3-none-win32.whl", hash = "sha256:e02794ac791662a5eafc6ffeaf9bcc149035a0e48eb0a9d40a8feb4622605a3d"}, - {file = "watchdog-2.1.6-py3-none-win_amd64.whl", hash = "sha256:bd9ba4f332cf57b2c1f698be0728c020399ef3040577cde2939f2e045b39c1e5"}, - {file = "watchdog-2.1.6-py3-none-win_ia64.whl", hash = "sha256:a0f1c7edf116a12f7245be06120b1852275f9506a7d90227648b250755a03923"}, - {file = "watchdog-2.1.6.tar.gz", hash = "sha256:a36e75df6c767cbf46f61a91c70b3ba71811dfa0aca4a324d9407a06a8b7a2e7"}, -] -wcwidth = [ - {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, - {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, -] -whitenoise = [ - {file = "whitenoise-6.0.0-py3-none-any.whl", hash = "sha256:5a4aff543ee860fbe40d743e556adf92ccd41b7df45697cae074afdf657056b9"}, - {file = "whitenoise-6.0.0.tar.gz", hash = "sha256:08c42bc535f9777eea1a599289d9433f081921f97887eaf6f559446b2a080374"}, -] +lock-version = "2.0" +python-versions = ">=3.10,<4.0" +content-hash = "5207d9544f3bacfd7990c320ca0d8496b37e8fdf5cd477c878257f907fafc55d" diff --git a/backend/projects/migrations/0008_project_allow_member_to_create_label_type_and_more.py b/backend/projects/migrations/0008_project_allow_member_to_create_label_type_and_more.py new file mode 100644 index 0000000000..af41b30737 --- /dev/null +++ b/backend/projects/migrations/0008_project_allow_member_to_create_label_type_and_more.py @@ -0,0 +1,36 @@ +# Generated by Django 4.1.7 on 2023-06-07 04:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("projects", "0007_imagecaptioningproject_alter_project_project_type"), + ] + + operations = [ + migrations.AddField( + model_name="project", + name="allow_member_to_create_label_type", + field=models.BooleanField(default=False), + ), + migrations.AlterField( + model_name="project", + name="project_type", + field=models.CharField( + choices=[ + ("DocumentClassification", "Document Classification"), + ("SequenceLabeling", "Sequence Labeling"), + ("Seq2seq", "Seq2Seq"), + ("IntentDetectionAndSlotFilling", "Intent Detection And Slot Filling"), + ("Speech2text", "Speech2Text"), + ("ImageClassification", "Image Classification"), + ("BoundingBox", "Bounding Box"), + ("Segmentation", "Segmentation"), + ("ImageCaptioning", "Image Captioning"), + ], + max_length=30, + ), + ), + ] diff --git a/backend/projects/models.py b/backend/projects/models.py index 7722a36945..bd5a2f26dd 100644 --- a/backend/projects/models.py +++ b/backend/projects/models.py @@ -1,4 +1,6 @@ import abc +import uuid +from typing import Any, Dict, Optional from django.conf import settings from django.contrib.auth.models import User @@ -9,26 +11,17 @@ from roles.models import Role -DOCUMENT_CLASSIFICATION = "DocumentClassification" -SEQUENCE_LABELING = "SequenceLabeling" -SEQ2SEQ = "Seq2seq" -SPEECH2TEXT = "Speech2text" -IMAGE_CLASSIFICATION = "ImageClassification" -BOUNDING_BOX = "BoundingBox" -SEGMENTATION = "Segmentation" -IMAGE_CAPTIONING = "ImageCaptioning" -INTENT_DETECTION_AND_SLOT_FILLING = "IntentDetectionAndSlotFilling" -PROJECT_CHOICES = ( - (DOCUMENT_CLASSIFICATION, "document classification"), - (SEQUENCE_LABELING, "sequence labeling"), - (SEQ2SEQ, "sequence to sequence"), - (INTENT_DETECTION_AND_SLOT_FILLING, "intent detection and slot filling"), - (SPEECH2TEXT, "speech to text"), - (IMAGE_CLASSIFICATION, "image classification"), - (BOUNDING_BOX, "bounding box"), - (SEGMENTATION, "segmentation"), - (IMAGE_CAPTIONING, "image captioning"), -) + +class ProjectType(models.TextChoices): + DOCUMENT_CLASSIFICATION = "DocumentClassification" + SEQUENCE_LABELING = "SequenceLabeling" + SEQ2SEQ = "Seq2seq" + INTENT_DETECTION_AND_SLOT_FILLING = "IntentDetectionAndSlotFilling" + SPEECH2TEXT = "Speech2text" + IMAGE_CLASSIFICATION = "ImageClassification" + BOUNDING_BOX = "BoundingBox" + SEGMENTATION = "Segmentation" + IMAGE_CAPTIONING = "ImageCaptioning" class Project(PolymorphicModel): @@ -42,10 +35,11 @@ class Project(PolymorphicModel): on_delete=models.SET_NULL, null=True, ) - project_type = models.CharField(max_length=30, choices=PROJECT_CHOICES) + project_type = models.CharField(max_length=30, choices=ProjectType.choices) random_order = models.BooleanField(default=False) collaborative_annotation = models.BooleanField(default=False) single_class_classification = models.BooleanField(default=False) + allow_member_to_create_label_type = models.BooleanField(default=False) def add_admin(self): admin_role = Role.objects.get(name=settings.ROLE_PROJECT_ADMIN) @@ -60,25 +54,53 @@ def add_admin(self): def is_text_project(self) -> bool: return False - @property - def can_define_label(self) -> bool: - """Whether or not the project can define label(ignoring the type of label)""" - return False - - @property - def can_define_relation(self) -> bool: - """Whether or not the project can define relation.""" - return False - - @property - def can_define_category(self) -> bool: - """Whether or not the project can define category.""" - return False + def clone(self) -> "Project": + """Clone the project. + See https://docs.djangoproject.com/en/4.2/topics/db/queries/#copying-model-instances - @property - def can_define_span(self) -> bool: - """Whether or not the project can define span.""" - return False + Returns: + The cloned project. + """ + project = Project.objects.get(pk=self.pk) + project.pk = None + project.id = None + project._state.adding = True + project.save() + + def bulk_clone(queryset: models.QuerySet, field_initializers: Optional[Dict[Any, Any]] = None): + """Clone the queryset. + + Args: + queryset: The queryset to clone. + field_initializers: The field initializers. + """ + if field_initializers is None: + field_initializers = {} + items = [] + for item in queryset: + item.id = None + item.pk = None + for field, value_or_callable in field_initializers.items(): + if callable(value_or_callable): + value_or_callable = value_or_callable() + setattr(item, field, value_or_callable) + item.project = project + item._state.adding = True + items.append(item) + queryset.model.objects.bulk_create(items) + + bulk_clone(self.role_mappings.all()) + bulk_clone(self.tags.all()) + + # clone examples + bulk_clone(self.examples.all(), field_initializers={"uuid": uuid.uuid4}) + + # clone label types + bulk_clone(self.categorytype_set.all()) + bulk_clone(self.spantype_set.all()) + bulk_clone(self.relationtype_set.all()) + + return project def __str__(self): return self.name @@ -89,14 +111,6 @@ class TextClassificationProject(Project): def is_text_project(self) -> bool: return True - @property - def can_define_label(self) -> bool: - return True - - @property - def can_define_category(self) -> bool: - return True - class SequenceLabelingProject(Project): allow_overlapping = models.BooleanField(default=False) @@ -107,14 +121,6 @@ class SequenceLabelingProject(Project): def is_text_project(self) -> bool: return True - @property - def can_define_label(self) -> bool: - return True - - @property - def can_define_span(self) -> bool: - return True - class Seq2seqProject(Project): @property @@ -127,18 +133,6 @@ class IntentDetectionAndSlotFillingProject(Project): def is_text_project(self) -> bool: return True - @property - def can_define_label(self) -> bool: - return True - - @property - def can_define_category(self) -> bool: - return True - - @property - def can_define_span(self) -> bool: - return True - class Speech2textProject(Project): @property @@ -151,42 +145,18 @@ class ImageClassificationProject(Project): def is_text_project(self) -> bool: return False - @property - def can_define_label(self) -> bool: - return True - - @property - def can_define_category(self) -> bool: - return True - class BoundingBoxProject(Project): @property def is_text_project(self) -> bool: return False - @property - def can_define_label(self) -> bool: - return True - - @property - def can_define_category(self) -> bool: - return True - class SegmentationProject(Project): @property def is_text_project(self) -> bool: return False - @property - def can_define_label(self) -> bool: - return True - - @property - def can_define_category(self) -> bool: - return True - class ImageCaptioningProject(Project): @property @@ -240,6 +210,9 @@ def clean(self): message = "This user is already assigned to a role in this project." raise ValidationError(message) + def is_admin(self): + return self.role.name == settings.ROLE_PROJECT_ADMIN + @property def username(self): return self.user.username diff --git a/backend/projects/serializers.py b/backend/projects/serializers.py index 51cd956d9e..861842d29e 100644 --- a/backend/projects/serializers.py +++ b/backend/projects/serializers.py @@ -49,6 +49,13 @@ class Meta: class ProjectSerializer(serializers.ModelSerializer): tags = TagSerializer(many=True, required=False) + author = serializers.SerializerMethodField() + + @classmethod + def get_author(cls, instance): + if instance.created_by: + return instance.created_by.username + return "" class Meta: model = Project @@ -58,25 +65,21 @@ class Meta: "description", "guideline", "project_type", + "created_at", "updated_at", "random_order", - "created_by", + "author", "collaborative_annotation", "single_class_classification", + "allow_member_to_create_label_type", "is_text_project", - "can_define_label", - "can_define_relation", - "can_define_category", - "can_define_span", "tags", ] read_only_fields = ( + "created_at", "updated_at", + "author", "is_text_project", - "can_define_label", - "can_define_relation", - "can_define_category", - "can_define_span", ) def create(self, validated_data): diff --git a/backend/projects/tests/test_project.py b/backend/projects/tests/test_project.py index ea69bee936..0c57dde9e3 100644 --- a/backend/projects/tests/test_project.py +++ b/backend/projects/tests/test_project.py @@ -1,9 +1,12 @@ from django.conf import settings +from django.test import TestCase from rest_framework import status from rest_framework.reverse import reverse from api.tests.utils import CRUDMixin -from projects.models import Member +from examples.tests.utils import make_doc +from label_types.tests.utils import make_label +from projects.models import Member, Project, ProjectType from projects.tests.utils import prepare_project from roles.tests.utils import create_default_roles from users.tests.utils import make_user @@ -124,3 +127,43 @@ def test_denies_project_staff_to_delete_project(self): def test_denies_non_member_to_delete_project(self): self.assert_delete(self.non_member, status.HTTP_403_FORBIDDEN) + + +class TestProjectModel(TestCase): + def setUp(self): + self.project = prepare_project().item + + def test_clone_project(self): + project = self.project.clone() + self.assertNotEqual(project.id, self.project.id) + self.assertEqual(project.name, self.project.name) + self.assertEqual(project.role_mappings.count(), self.project.role_mappings.count()) + + +class TestCloneProject(CRUDMixin): + @classmethod + def setUpTestData(cls): + project = prepare_project(task=ProjectType.DOCUMENT_CLASSIFICATION) + cls.project = project.item + cls.user = project.admin + make_doc(cls.project) + cls.category_type = make_label(cls.project) + cls.url = reverse(viewname="clone_project", args=[cls.project.id]) + + def test_clone_project(self): + response = self.assert_create(self.user, status.HTTP_201_CREATED) + + project = Project.objects.get(id=response.data["id"]) + + # assert project + self.assertNotEqual(project.id, self.project.id) + self.assertEqual(project.name, self.project.name) + + # assert category type + category_type = project.categorytype_set.first() + self.assertEqual(category_type.text, self.category_type.text) + + # assert example + example = self.project.examples.first() + cloned_example = project.examples.first() + self.assertEqual(example.text, cloned_example.text) diff --git a/backend/projects/tests/utils.py b/backend/projects/tests/utils.py index f3a30b2057..fe55bad328 100644 --- a/backend/projects/tests/utils.py +++ b/backend/projects/tests/utils.py @@ -3,19 +3,7 @@ from django.conf import settings from model_mommy import mommy -from projects.models import ( - BOUNDING_BOX, - DOCUMENT_CLASSIFICATION, - IMAGE_CAPTIONING, - IMAGE_CLASSIFICATION, - INTENT_DETECTION_AND_SLOT_FILLING, - SEGMENTATION, - SEQ2SEQ, - SEQUENCE_LABELING, - SPEECH2TEXT, - Member, - Role, -) +from projects.models import Member, ProjectType, Role from roles.tests.utils import create_default_roles from users.tests.utils import make_user @@ -65,15 +53,15 @@ def make_project(task: str, users: List[str], roles: List[str], collaborative_an # create a project. project_model = { - DOCUMENT_CLASSIFICATION: "TextClassificationProject", - SEQUENCE_LABELING: "SequenceLabelingProject", - SEQ2SEQ: "Seq2seqProject", - SPEECH2TEXT: "Speech2TextProject", - IMAGE_CLASSIFICATION: "ImageClassificationProject", - INTENT_DETECTION_AND_SLOT_FILLING: "IntentDetectionAndSlotFillingProject", - BOUNDING_BOX: "BoundingBoxProject", - SEGMENTATION: "SegmentationProject", - IMAGE_CAPTIONING: "ImageCaptioningProject", + ProjectType.DOCUMENT_CLASSIFICATION: "TextClassificationProject", + ProjectType.SEQUENCE_LABELING: "SequenceLabelingProject", + ProjectType.SEQ2SEQ: "Seq2seqProject", + ProjectType.SPEECH2TEXT: "Speech2TextProject", + ProjectType.IMAGE_CLASSIFICATION: "ImageClassificationProject", + ProjectType.INTENT_DETECTION_AND_SLOT_FILLING: "IntentDetectionAndSlotFillingProject", + ProjectType.BOUNDING_BOX: "BoundingBoxProject", + ProjectType.SEGMENTATION: "SegmentationProject", + ProjectType.IMAGE_CAPTIONING: "ImageCaptioningProject", }.get(task, "Project") project = mommy.make( _model=project_model, diff --git a/backend/projects/urls.py b/backend/projects/urls.py index 2f67641bdf..490764b793 100644 --- a/backend/projects/urls.py +++ b/backend/projects/urls.py @@ -1,7 +1,7 @@ from django.urls import path from .views.member import MemberDetail, MemberList, MyRole -from .views.project import ProjectDetail, ProjectList +from .views.project import CloneProject, ProjectDetail, ProjectList from .views.tag import TagDetail, TagList urlpatterns = [ @@ -11,5 +11,6 @@ path(route="projects//tags", view=TagList.as_view(), name="tag_list"), path(route="projects//tags/", view=TagDetail.as_view(), name="tag_detail"), path(route="projects//members", view=MemberList.as_view(), name="member_list"), + path(route="projects//clone", view=CloneProject.as_view(), name="clone_project"), path(route="projects//members/", view=MemberDetail.as_view(), name="member_detail"), ] diff --git a/backend/projects/views/project.py b/backend/projects/views/project.py index 274388528f..47c735453f 100644 --- a/backend/projects/views/project.py +++ b/backend/projects/views/project.py @@ -1,6 +1,8 @@ from django.conf import settings +from django.db import transaction +from django.shortcuts import get_object_or_404 from django_filters.rest_framework import DjangoFilterBackend -from rest_framework import filters, generics, status +from rest_framework import filters, generics, status, views from rest_framework.permissions import IsAdminUser, IsAuthenticated from rest_framework.response import Response @@ -13,6 +15,8 @@ class ProjectList(generics.ListCreateAPIView): serializer_class = ProjectPolymorphicSerializer filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter) search_fields = ("name", "description") + ordering_fields = ["name", "created_at", "created_by", "project_type"] + ordering = ["-created_at"] def get_permissions(self): if self.request.method == "GET": @@ -50,3 +54,14 @@ class ProjectDetail(generics.RetrieveUpdateDestroyAPIView): serializer_class = ProjectPolymorphicSerializer lookup_url_kwarg = "project_id" permission_classes = [IsAuthenticated & (IsProjectAdmin | IsProjectStaffAndReadOnly)] + + +class CloneProject(views.APIView): + permission_classes = [IsAuthenticated & IsProjectAdmin] + + @transaction.atomic + def post(self, request, *args, **kwargs): + project = get_object_or_404(Project, pk=self.kwargs["project_id"]) + cloned_project = project.clone() + serializer = ProjectPolymorphicSerializer(cloned_project) + return Response(serializer.data, status=status.HTTP_201_CREATED) diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 472a3636e1..683246e5d3 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "doccano" -version = "1.8.0" +version = "1.8.5" description = "doccano, text annotation tool for machine learning practitioners" authors = ["Hironsan "] license = "MIT" @@ -10,7 +10,9 @@ repository = "https://github.com/doccano/doccano" documentation = "https://doccano.github.io/doccano/" classifiers = [ "Programming Language :: Python", - "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] packages = [ { include = "backend", from = ".." }, @@ -34,15 +36,12 @@ postgresql = ["psycopg2-binary"] doccano = 'backend.cli:main' [tool.poetry.dependencies] -python = "^3.8" -Django = "^4.0.2" -environs = "^9.5.0" +python = ">=3.10,<4.0" +Django = "^4.1.7" furl = "^2.1.3" -djangorestframework = "^3.13.1" -django-filter = "^21.1" -django-polymorphic = "^3.1.0" -django-cors-headers = "^3.11.0" -drf-yasg = "^1.20.0" +djangorestframework = "^3.14.0" +django-filter = "^22.1" +django-cors-headers = "^3.13.0" django-rest-polymorphic = "^0.1.9" chardet = "^4.0.0" pyexcel = "^0.7.0" @@ -50,20 +49,26 @@ seqeval = "^1.2.2" whitenoise = "^6.0.0" dj-database-url = "^0.5.0" pyexcel-xlsx = "^0.6.0" -gunicorn = "^20.1.0" +gunicorn = "^23.0.0" auto-labeling-pipeline = "^0.1.21" -dj-rest-auth = "^2.2.3" -django-drf-filepond = "^0.4.1" +dj-rest-auth = {extras = ["with_social"], version = "^2.2.5"} +django-drf-filepond = "^0.5.0" celery = "^5.2.3" -django-celery-results = "2.2.0" +django-celery-results = "2.4.0" SQLAlchemy = "^1.4.31" -waitress = "^2.0.0" django-health-check = "^3.16.5" djangorestframework-xml = "^2.0.0" -django-storages = {extras = ["google"], version = "^1.12.3"} +django-storages = {extras = ["google"], version = "^1.13.1"} django-cleanup = "^6.0.0" filetype = "^1.0.10" -pandas = "^1.4.2" +flower = "^1.2.0" +django-allauth = "^0.52.0" +pydantic = "^2.0.3" +environs = "^14.5.0" +django-polymorphic = "^4.9.0" +drf-yasg = "^1.21.11" +pandas = "^2.3.3" +waitress = "^3.0.2" [tool.poetry.dev-dependencies] model-mommy = "^2.0.0" @@ -71,9 +76,8 @@ coverage = "^6.3.1" flake8 = "^4.0.1" isort = {extras = ["pyproject"], version = "^5.10.1"} autopep8 = "^1.6.0" -mypy = "^0.931" +mypy = "^1.4.1" watchdog = "^2.1.6" -black = "^22.1.0" pyproject-flake8 = "^0.0.1-alpha.2" types-chardet = "^4.0.3" types-requests = "^2.27.10" @@ -81,6 +85,9 @@ types-waitress = "^2.0.6" taskipy = "^1.10.1" unittest-xml-reporting = "^3.2.0" +[tool.poetry.group.dev.dependencies] +black = "^25.12.0" + [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" @@ -90,17 +97,17 @@ enable = false [tool.black] line-length = 120 -target-version = ['py37', 'py38'] +target-version = ['py310'] include = '\.pyi?$' [tool.flake8] max-line-length = 120 max-complexity = 18 -ignore = "E203,E266,W503," +ignore = "E203,E266,W503,E704" filename = "*.py" [tool.mypy] -python_version = "3.8" +python_version = "3.10" ignore_missing_imports = true show_error_codes = true exclude = [ @@ -124,7 +131,8 @@ known_first_party = [ "metrics", "projects", "roles", - "users" + "users", + "social" ] known_local_folder = [ "api", @@ -138,7 +146,8 @@ known_local_folder = [ "metrics", "projects", "roles", - "users" + "users", + "social" ] [tool.taskipy.tasks] diff --git a/backend/social/__init__.py b/backend/social/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/backend/social/admin.py b/backend/social/admin.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/backend/social/apps.py b/backend/social/apps.py new file mode 100644 index 0000000000..567a89b78e --- /dev/null +++ b/backend/social/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class SocialConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "social" diff --git a/backend/social/models.py b/backend/social/models.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/backend/social/okta.py b/backend/social/okta.py new file mode 100644 index 0000000000..3f85b34f7d --- /dev/null +++ b/backend/social/okta.py @@ -0,0 +1,9 @@ +from allauth.socialaccount.providers.oauth2.client import OAuth2Client +from allauth.socialaccount.providers.okta.views import OktaOAuth2Adapter +from dj_rest_auth.registration.views import SocialLoginView + + +class OktaLogin(SocialLoginView): + adapter_class = OktaOAuth2Adapter + callback_url = "/projects" + client_class = OAuth2Client diff --git a/backend/social/urls.py b/backend/social/urls.py new file mode 100644 index 0000000000..faa53f593b --- /dev/null +++ b/backend/social/urls.py @@ -0,0 +1,7 @@ +from django.urls import path + +from .okta import OktaLogin + +urlpatterns = [ + path("complete/okta-oauth2/", OktaLogin.as_view(), name="okta_login"), +] diff --git a/backend/social/v1_urls.py b/backend/social/v1_urls.py new file mode 100644 index 0000000000..61cba70cd9 --- /dev/null +++ b/backend/social/v1_urls.py @@ -0,0 +1,7 @@ +from django.urls import path + +from .views import Social + +urlpatterns = [ + path("links/", Social.as_view()), +] diff --git a/backend/social/views.py b/backend/social/views.py new file mode 100644 index 0000000000..6c40b95b6a --- /dev/null +++ b/backend/social/views.py @@ -0,0 +1,28 @@ +from django.conf import settings +from rest_framework.response import Response +from rest_framework.views import APIView + + +class Social(APIView): + permission_classes = () + + def get(self, request, *args, **kwargs): + return Response( + { + "okta": ( + { + "type": "oauth2", + "base_url": settings.SOCIALACCOUNT_PROVIDERS.get("okta").get("OKTA_BASE_URL"), + "client_id": settings.SOCIALACCOUNT_PROVIDERS.get("okta").get("APP").get("client_id"), + "redirect_path": "/social/complete/okta-oauth2", + "authorize_url": "https://" + + settings.SOCIALACCOUNT_PROVIDERS.get("okta").get("OKTA_BASE_URL") + + "/oauth2/v1/authorize?response_type=code&client_id=" + + settings.SOCIALACCOUNT_PROVIDERS.get("okta").get("APP").get("client_id") + + "&scope=openid&state=unknown&response_mode=form_post", + } + if settings.SOCIALACCOUNT_PROVIDERS.get("okta").get("OKTA_BASE_URL") + else {} + ), + } + ) diff --git a/backend/users/tests/test_views.py b/backend/users/tests/test_views.py index 13f534f63a..dea5117021 100644 --- a/backend/users/tests/test_views.py +++ b/backend/users/tests/test_views.py @@ -38,3 +38,22 @@ def test_return_own_information(self): def test_does_not_return_information_to_unauthenticated_user(self): response = self.client.get(self.url) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + +class TestUserCreationAPI(APITestCase): + @classmethod + def setUpTestData(cls): + cls.staff = make_user(username="bob", is_staff=True) + cls.non_staff = make_user(username="tom", is_staff=False) + cls.url = reverse(viewname="user_create") + cls.payload = {"username": "hironsan", "password1": "foobarbaz", "password2": "foobarbaz"} + + def test_staff_can_create_user(self): + self.client.force_login(self.staff) + response = self.client.post(self.url, data=self.payload) + self.assertEqual(response.data["username"], "hironsan") + + def test_non_staff_cannot_create_user(self): + self.client.force_login(self.non_staff) + response = self.client.post(self.url, data=self.payload) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) diff --git a/backend/users/tests/utils.py b/backend/users/tests/utils.py index f3492efb6e..dffabbb152 100644 --- a/backend/users/tests/utils.py +++ b/backend/users/tests/utils.py @@ -1,7 +1,7 @@ from django.contrib.auth import get_user_model -def make_user(username: str = "bob"): +def make_user(username: str = "bob", is_staff: bool = False): user_model = get_user_model() - user, _ = user_model.objects.get_or_create(username=username, password="pass") + user, _ = user_model.objects.get_or_create(username=username, password="pass", is_staff=is_staff) return user diff --git a/backend/users/urls.py b/backend/users/urls.py index cadbc1dab9..47b04439b8 100644 --- a/backend/users/urls.py +++ b/backend/users/urls.py @@ -1,9 +1,10 @@ from django.urls import include, path -from .views import Me, Users +from .views import Me, UserCreation, Users urlpatterns = [ path(route="me", view=Me.as_view(), name="me"), path(route="users", view=Users.as_view(), name="user_list"), + path(route="users/create", view=UserCreation.as_view(), name="user_create"), path("auth/", include("dj_rest_auth.urls")), ] diff --git a/backend/users/views.py b/backend/users/views.py index c21ddc54fe..e8fd8ee4e8 100644 --- a/backend/users/views.py +++ b/backend/users/views.py @@ -1,7 +1,8 @@ +from dj_rest_auth.registration.serializers import RegisterSerializer from django.contrib.auth.models import User from django_filters.rest_framework import DjangoFilterBackend -from rest_framework import filters, generics -from rest_framework.permissions import IsAuthenticated +from rest_framework import filters, generics, status +from rest_framework.permissions import IsAdminUser, IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView @@ -24,3 +25,19 @@ class Users(generics.ListAPIView): pagination_class = None filter_backends = (DjangoFilterBackend, filters.SearchFilter) search_fields = ("username",) + + +class UserCreation(generics.CreateAPIView): + serializer_class = RegisterSerializer + permission_classes = [IsAuthenticated & IsAdminUser] + + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + user = self.perform_create(serializer) + headers = self.get_success_headers(serializer.data) + return Response(UserSerializer(user).data, status=status.HTTP_201_CREATED, headers=headers) + + def perform_create(self, serializer): + user = serializer.save(self.request) + return user diff --git a/cloud/aws/template.aws.yaml b/cloud/aws/template.aws.yaml index d80f3ad762..5ab144ca04 100644 --- a/cloud/aws/template.aws.yaml +++ b/cloud/aws/template.aws.yaml @@ -18,9 +18,8 @@ Parameters: InstanceType: Description: WebServer EC2 instance type Type: String - Default: t2.small + Default: t2.medium AllowedValues: - - t2.small - t2.medium - t2.large ConstraintDescription: must be a valid EC2 instance type. diff --git a/cloud/azure/azure-pipelines.yaml b/cloud/azure/azure-pipelines.yaml deleted file mode 100644 index 12da7d8602..0000000000 --- a/cloud/azure/azure-pipelines.yaml +++ /dev/null @@ -1,54 +0,0 @@ -trigger: -- master - -pool: - vmImage: 'ubuntu-latest' - -steps: -- script: docker build --tag=doccano --target=builder . - displayName: 'Run tests' - -- script: docker run doccano tar Ccf /doccano/app - junitxml | tar Cxf "$(Build.ArtifactStagingDirectory)" - - displayName: 'Export test results' - -- task: PublishTestResults@2 - inputs: - testResultsFormat: 'JUnit' - testResultsFiles: 'TEST-*.xml' - searchFolder: '$(Build.ArtifactStagingDirectory)/junitxml' - mergeTestResults: true - testRunTitle: 'server.tests' - displayName: 'Publish test results' - -# To publish docker images to a container registry, set the following pipeline variables: -# - docker_password -# - docker_username -# - docker_registry (optional, set this to publish to a registry other than Docker Hub) -# -- script: DOCKER_PASSWORD="$(docker_password)" tools/cd.sh "azdo-$(Build.BuildId)" - displayName: 'Push docker image' - condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'), ne(variables['docker_password'], '')) - -# To automatically deploy to Azure, create a service principal and set the following pipeline variables: -# - auth_username (app ID) -# - auth_tenant (tenant ID -# - auth_password (secret) -# -# Additionally, to configure the deployment, set the following pipeline variables: -# - doccano_admin_username -# - doccano_admin_password -# - doccano_admin_contact_email -# - doccano_app_name (globally unique name for the app) -# - doccano_secret_key (pass-through secret for Django) -# - doccano_resource_group (group for all resources, will be created if it doesn't yet exist) -# - doccano_location (name of the Azure region to which to deploy all resources) -# -- script: | - az login --service-principal --password "$(auth_password)" --tenant "$(auth_tenant)" --username "$(auth_username)" - - DOCCANO_ADMIN_PASSWORD="$(doccano_admin_password)" \ - DOCCANO_SECRET_KEY="$(doccano_secret_key)" \ - DOCKER_PASSWORD="$(docker_password)" \ - tools/azure.sh "azdo-$(Build.BuildId)" - displayName: 'Deploy to Azure' - condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'), ne(variables['auth_password'], '')) diff --git a/cloud/azure/azuredeploy.json b/cloud/azure/azuredeploy.json deleted file mode 100644 index 07977d954c..0000000000 --- a/cloud/azure/azuredeploy.json +++ /dev/null @@ -1,347 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "appName": { - "type": "string", - "minLength": 1, - "metadata": { - "description": "The name for the webapp. Must be globally unique." - } - }, - "secretKey": { - "type": "securestring", - "minLength": 16, - "metadata": { - "description": "The value to use as the Django secret key." - } - }, - "adminUserName": { - "type": "string", - "minLength": 1, - "metadata": { - "description": "The user name for the admin account." - } - }, - "adminContactEmail": { - "type": "string", - "minLength": 1, - "metadata": { - "description": "The contact email address for the admin account." - } - }, - "adminPassword": { - "type": "securestring", - "minLength": 16, - "maxLength": 50, - "metadata": { - "description": "The password for the admin account." - } - }, - "appServiceSku": { - "type": "string", - "defaultValue": "B2", - "allowedValues": [ - "B1", - "B2", - "B3", - "S1", - "S2", - "S3" - ], - "metadata": { - "description": "The SKU of the webapp hosting tier." - } - }, - "sendgridSku": { - "type": "string", - "defaultValue": "free", - "allowedValues": [ - "free", - "bronze", - "silver", - "gold", - "platinum", - "premier" - ], - "metadata": { - "description": "The SKU of the Sendgrid email account." - } - }, - "databaseCores": { - "type": "int", - "defaultValue": 2, - "allowedValues": [ - 2, - 4, - 8, - 16, - 32, - 64 - ], - "metadata": { - "description": "The number of vCores to provision for the PostgreSQL server." - } - }, - "databaseSize": { - "type": "int", - "minValue": 51200, - "defaultValue": 51200, - "metadata": { - "description": "The storage capacity to provision for the PostgreSQL server." - } - }, - "databaseName": { - "type": "string", - "minLength": 1, - "defaultValue": "doccano", - "metadata": { - "description": "The name of the database to provision on the PostgreSQL server." - } - }, - "dockerImageName": { - "type": "string", - "minLength": 1, - "defaultValue": "doccano/doccano:latest", - "metadata": { - "description": "The Docker image to deploy." - } - }, - "dockerRegistry": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The registry of the Docker image." - } - }, - "dockerRegistryUserName": { - "type": "string", - "defaultValue": "", - "metadata": { - "description": "The user name for the Docker registry." - } - }, - "dockerRegistryPassword": { - "type": "securestring", - "defaultValue": "", - "metadata": { - "description": "The password for the Docker registry." - } - } - }, - "variables": { - "location": "[resourceGroup().location]", - "databaseSkuTier": "GeneralPurpose", - "databaseSkuFamily": "Gen5", - "databaseSkuName": "[concat('GP_', variables('databaseSkuFamily'), '_', parameters('databaseCores'))]", - "databaseVersion": "9.6", - "databaseServerPort": 5432, - "databaseServerName": "[concat(parameters('appName'),'-state')]", - "databaseUserCredentials" : "[concat(uriComponent(concat(parameters('adminUserName'), '@', variables('databaseServerName'))), ':', parameters('adminPassword'))]", - "databaseFqdn" : "[concat( variables('databaseServerName'), '.postgres.database.azure.com:', variables('databaseServerPort'))]", - "databaseConnectionString": "[concat('pgsql://', variables('databaseUserCredentials'), '@', variables('databaseFqdn'), '/', parameters('databaseName'))]", - "sendgridAccountName": "[concat(parameters('appName'),'-email')]", - "appServicePlanName": "[concat(parameters('appName'),'-hosting')]", - "analyticsName": "[concat(parameters('appName'),'-analytics')]", - "appFqdn": "[concat(parameters('appName'),'.azurewebsites.net')]" - }, - "resources": [ - { - "name": "[variables('sendgridAccountName')]", - "type": "Sendgrid.Email/accounts", - "apiVersion": "2015-01-01", - "location": "[variables('location')]", - "plan": { - "name": "[parameters('sendgridSku')]", - "publisher": "Sendgrid", - "product": "sendgrid_azure", - "promotionCode": "" - }, - "properties": { - "acceptMarketingEmails": false, - "email": "[parameters('adminContactEmail')]", - "password": "[parameters('adminPassword')]" - } - }, - { - "type": "Microsoft.Insights/components", - "apiVersion": "2015-05-01", - "name": "[variables('analyticsName')]", - "location": "[variables('location')]", - "tags": {}, - "kind": "web", - "properties": { - "Application_Type": "web" - } - }, - { - "apiVersion": "2017-08-01", - "type": "Microsoft.Web/serverfarms", - "kind": "linux", - "name": "[variables('appServicePlanName')]", - "location": "[variables('location')]", - "properties": { - "reserved": true - }, - "dependsOn": [], - "sku": { - "name": "[parameters('appServiceSku')]" - } - }, - { - "apiVersion": "2017-12-01", - "type": "Microsoft.DBforPostgreSQL/servers", - "location": "[variables('location')]", - "name": "[variables('databaseServerName')]", - "sku": { - "name": "[variables('databaseSkuName')]", - "tier": "[variables('databaseSkuTier')]", - "family": "[variables('databaseSkuFamily')]", - "capacity": "[parameters('databaseCores')]", - "size": "[parameters('databaseSize')]" - }, - "properties": { - "version": "[variables('databaseVersion')]", - "administratorLogin": "[parameters('adminUserName')]", - "administratorLoginPassword": "[parameters('adminPassword')]", - "storageMB": "[parameters('databaseSize')]" - }, - "resources": [ - { - "name": "allowAzure", - "type": "firewallrules", - "apiVersion": "2017-12-01", - "location": "[variables('location')]", - "properties": { - "startIpAddress": "0.0.0.0", - "endIpAddress": "0.0.0.0" - }, - "dependsOn": [ - "[resourceId('Microsoft.DBforPostgreSQL/servers/', variables('databaseServerName'))]" - ] - }, - { - "name": "[parameters('databaseName')]", - "type": "databases", - "apiVersion": "2017-12-01", - "properties": { - "charset": "utf8", - "collation": "English_United States.1252" - }, - "dependsOn": [ - "[resourceId('Microsoft.DBforPostgreSQL/servers/', variables('databaseServerName'))]" - ] - } - ] - }, - { - "type": "Microsoft.Web/sites", - "apiVersion": "2016-08-01", - "name": "[parameters('appName')]", - "kind": "app,linux,container", - "location": "[variables('location')]", - "dependsOn": [ - "[resourceId('Sendgrid.Email/accounts', variables('sendgridAccountName'))]", - "[resourceId('Microsoft.DBforPostgreSQL/servers/', variables('databaseServerName'))]", - "[resourceId('Microsoft.Insights/components', variables('analyticsName'))]", - "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]" - ], - "properties": { - "name": "[parameters('appName')]", - "siteConfig": { - "linuxFxVersion": "[concat('DOCKER|', parameters('dockerImageName'))]", - "alwaysOn": true, - "appSettings": [ - { - "name": "WEBSITES_PORT", - "value": "8000" - }, - { - "name": "PORT", - "value": "8000" - }, - { - "name": "WEBSITES_ENABLE_APP_SERVICE_STORAGE", - "value": "false" - }, - { - "name": "DOCKER_REGISTRY_SERVER_URL", - "value": "[parameters('dockerRegistry')]" - }, - { - "name": "DOCKER_REGISTRY_SERVER_USERNAME", - "value": "[parameters('dockerRegistryUserName')]" - }, - { - "name": "DOCKER_REGISTRY_SERVER_PASSWORD", - "value": "[parameters('dockerRegistryPassword')]" - }, - { - "name": "AZURE_APPINSIGHTS_IKEY", - "value": "[reference(resourceId('Microsoft.Insights/components', variables('analyticsName')), '2014-04-01').InstrumentationKey]" - }, - { - "name": "GOOGLE_TRACKING_ID", - "value": " " - }, - { - "name": "ADMIN_USERNAME", - "value": "[parameters('adminUserName')]" - }, - { - "name": "ADMIN_EMAIL", - "value": "[parameters('adminContactEmail')]" - }, - { - "name": "ADMIN_PASSWORD", - "value": "[parameters('adminPassword')]" - }, - { - "name": "EMAIL_USE_TLS", - "value": "True" - }, - { - "name": "EMAIL_HOST", - "value": "[reference(resourceId('Sendgrid.Email/accounts', variables('sendgridAccountName'))).smtpServer]" - }, - { - "name": "EMAIL_HOST_USER", - "value": "[reference(resourceId('Sendgrid.Email/accounts', variables('sendgridAccountName'))).username]" - }, - { - "name": "EMAIL_HOST_PASSWORD", - "value": "[parameters('adminPassword')]" - }, - { - "name": "EMAIL_PORT", - "value": "587" - }, - { - "name": "DEBUG", - "value": "False" - }, - { - "name": "SECRET_KEY", - "value": "[parameters('secretKey')]" - }, - { - "name": "DATABASE_URL", - "value": "[variables('databaseConnectionString')]" - } - ] - }, - "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('appServicePlanName'))]" - } - } - ], - "outputs": { - "appServer": { - "type": "string", - "value": "[concat(variables('appFqdn'))]" - }, - "databaseServer": { - "type": "string", - "value": "[variables('databaseFqdn')]" - } - } -} diff --git a/cloud/gcp/cloudbuild.yaml b/cloud/gcp/cloudbuild.yaml deleted file mode 100644 index eb4f4d2d98..0000000000 --- a/cloud/gcp/cloudbuild.yaml +++ /dev/null @@ -1,7 +0,0 @@ -steps: -- name: 'gcr.io/cloud-builders/docker' - args: ['build', '--tag=gcr.io/${PROJECT_ID}/almeta-doccano:${BRANCH_NAME}', '.'] -- name: 'gcr.io/cloud-builders/docker' - args: ["push", "gcr.io/${PROJECT_ID}/almeta-doccano:${BRANCH_NAME}"] -- name: 'gcr.io/cloud-builders/gcloud' - args: ['beta', 'run', 'deploy', 'almeta-doccano', '--image', 'gcr.io/${PROJECT_ID}/almeta-doccano:${BRANCH_NAME}', '--region', 'us-central1', '--memory', '2G', '--platform', 'managed', '--allow-unauthenticated'] diff --git a/docker/.env.example b/docker/.env.example index a02aa927e9..7d4410244f 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -3,7 +3,6 @@ ADMIN_USERNAME=admin ADMIN_PASSWORD=password ADMIN_EMAIL=admin@example.com - # rabbit mq settings RABBITMQ_DEFAULT_USER=doccano RABBITMQ_DEFAULT_PASS=doccano @@ -11,4 +10,7 @@ RABBITMQ_DEFAULT_PASS=doccano # database settings POSTGRES_USER=doccano POSTGRES_PASSWORD=doccano -POSTGRES_DB=doccano \ No newline at end of file +POSTGRES_DB=doccano + +# Flower settings +FLOWER_BASIC_AUTH="" diff --git a/docker/Dockerfile b/docker/Dockerfile index 7d09665fb5..5aa5519406 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,5 +1,5 @@ -ARG PYTHON_VERSION="3.8.12-slim-buster" -ARG NODE_VERSION="16.14-buster-slim" +ARG PYTHON_VERSION="3.10.19-slim-trixie" +ARG NODE_VERSION="18.20-bullseye-slim" FROM node:${NODE_VERSION} AS frontend-builder COPY frontend/ /frontend/ @@ -9,7 +9,7 @@ ENV PUBLIC_PATH="/static/_nuxt/" RUN apt-get update \ && apt-get install -y --no-install-recommends git python3 make g++ ca-certificates \ && git config --global url."https://github.com/".insteadOf git://github.com/ \ - && yarn install \ + && yarn install --network-timeout 1000000 \ && yarn build \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* @@ -19,12 +19,11 @@ FROM python:${PYTHON_VERSION} AS backend-builder # hadolint ignore=DL3008 RUN apt-get update \ && apt-get install -y --no-install-recommends \ - netcat=1.* \ - libpq-dev=11.* \ + libpq-dev=17.* \ unixodbc-dev=2.* \ g++=4:* \ - libssl-dev=1.* \ - curl \ + libssl-dev=3.* \ + curl=8.* \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* @@ -32,9 +31,9 @@ WORKDIR /tmp COPY backend/pyproject.toml backend/poetry.lock /tmp/ SHELL ["/bin/bash", "-o", "pipefail", "-c"] -RUN pip install --no-cache-dir pip==22.0.4 \ - && curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - \ - && PATH="${PATH}:$HOME/.poetry/bin" \ +RUN pip install -U --no-cache-dir pip==25.3 \ + && curl -sSL https://install.python-poetry.org | POETRY_VERSION=1.5.1 python - \ + && export PATH="/root/.local/bin:$PATH" \ && poetry export --without-hashes -o /requirements.txt \ && echo "psycopg2-binary==2.8.6" >> /requirements.txt \ && echo "django-heroku==0.3.1" >> /requirements.txt \ @@ -44,9 +43,9 @@ FROM python:${PYTHON_VERSION} AS runtime RUN apt-get update \ && apt-get install -y --no-install-recommends \ - libpq-dev=11.* \ + libpq-dev=17.* \ unixodbc-dev=2.* \ - libssl-dev=1.* \ + libssl-dev=3.* \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* @@ -54,7 +53,7 @@ RUN useradd -ms /bin/sh doccano RUN mkdir /data \ && chown doccano:doccano /data -COPY --from=backend-builder /usr/local/lib/python3.8/site-packages /usr/local/lib/python3.8/site-packages +COPY --from=backend-builder /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages COPY --from=backend-builder /usr/local/bin/celery /usr/local/bin/celery COPY --from=backend-builder /usr/local/bin/gunicorn /usr/local/bin/gunicorn diff --git a/docker/Dockerfile.heroku b/docker/Dockerfile.heroku index 016c0d0fed..92fc65f952 100644 --- a/docker/Dockerfile.heroku +++ b/docker/Dockerfile.heroku @@ -1 +1 @@ -FROM doccano/doccano:master +FROM doccano/doccano:nightly diff --git a/docker/Dockerfile.nginx b/docker/Dockerfile.nginx index 9f78979c2b..6343894bd3 100644 --- a/docker/Dockerfile.nginx +++ b/docker/Dockerfile.nginx @@ -1,4 +1,4 @@ -ARG NODE_VERSION="16.14-buster-slim" +ARG NODE_VERSION="18.20-bullseye-slim" FROM node:${NODE_VERSION} AS frontend-builder COPY frontend/ /app/ @@ -7,7 +7,7 @@ WORKDIR /app RUN apt-get update \ && apt-get install -y --no-install-recommends git python3 make g++ ca-certificates \ && git config --global url."https://github.com/".insteadOf git://github.com/ \ - && yarn install \ + && yarn install --network-timeout 1000000 \ && yarn build \ && apt-get clean @@ -17,12 +17,13 @@ RUN addgroup -g 61000 doccano \ && adduser -G doccano -S doccano -u 61000 COPY --chown=doccano:doccano --from=frontend-builder /app/dist /var/www/html -COPY docker/nginx/nginx.conf /etc/nginx/nginx.conf +COPY docker/nginx/nginx.conf.template /etc/nginx/nginx.conf.template COPY docker/nginx/default.conf /etc/nginx/conf.d/default.conf RUN chown -R doccano:doccano /var/cache/nginx \ && chmod -R g+w /var/cache/nginx \ - && chown -R doccano:doccano /media + && chown -R doccano:doccano /media \ + && chown -R doccano:doccano /etc/nginx EXPOSE 8080 diff --git a/docker/Dockerfile.prod b/docker/Dockerfile.prod index 8ce8d9f70a..8222da2824 100644 --- a/docker/Dockerfile.prod +++ b/docker/Dockerfile.prod @@ -1,45 +1,56 @@ -ARG PYTHON_VERSION="3.8.12-slim-buster" -FROM python:${PYTHON_VERSION} +ARG PYTHON_VERSION="3.10.19-slim-trixie" +FROM python:${PYTHON_VERSION} AS backend-builder -CMD ["python3"] +# hadolint ignore=DL3008 +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + libpq-dev=17.* \ + unixodbc-dev=2.* \ + g++=4:* \ + libssl-dev=3.* \ + curl=8.* \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* -WORKDIR /backend +WORKDIR /tmp +COPY backend/pyproject.toml backend/poetry.lock /tmp/ +SHELL ["/bin/bash", "-o", "pipefail", "-c"] -ENV PYTHONDONTWRITEBYTECODE 1 -ENV PYTHONUNBUFFERED 1 +RUN pip install -U --no-cache-dir pip==25.3 \ + && curl -sSL https://install.python-poetry.org | POETRY_VERSION=1.5.1 python - \ + && export PATH="/root/.local/bin:$PATH" \ + && poetry export --without-hashes -o /requirements.txt \ + && echo "psycopg2-binary==2.8.6" >> /requirements.txt \ + && pip install --no-cache-dir -r /requirements.txt -RUN groupadd -g 61000 doccano \ - && useradd -g 61000 -l -M -s /bin/false -u 61000 doccano +FROM python:${PYTHON_VERSION} AS runtime -COPY --chown=doccano:doccano backend/pyproject.toml backend/poetry.lock /backend/ -SHELL ["/bin/bash", "-o", "pipefail", "-c"] +WORKDIR /backend -# hadolint ignore=DL3013,DL3008 RUN apt-get update \ && apt-get install -y --no-install-recommends \ - netcat=1.* \ - libpq-dev=11.* \ + libpq-dev=17.* \ unixodbc-dev=2.* \ - g++=4:* \ - curl \ - && pip install --upgrade --no-cache-dir pip \ - && curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - \ - && PATH="${PATH}:$HOME/.poetry/bin" \ - && poetry config virtualenvs.create false \ - && poetry install --no-dev --no-root \ - && poetry add psycopg2-binary \ + libssl-dev=3.* \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* +RUN groupadd -g 61000 doccano \ + && useradd -g 61000 -l -M -s /bin/false -u 61000 doccano + +COPY --from=backend-builder /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages +COPY --from=backend-builder /usr/local/bin/celery /usr/local/bin/celery +COPY --from=backend-builder /usr/local/bin/gunicorn /usr/local/bin/gunicorn COPY --chown=doccano:doccano tools/ /opt/bin/ +COPY --chown=doccano:doccano backend/ /backend/ RUN mkdir -p /backend/staticfiles \ && mkdir -p /backend/client/dist/static \ && mkdir -p /backend/media \ && mkdir -p /backend/filepond-temp-uploads \ && chown -R doccano:doccano /backend/ -COPY --chown=doccano:doccano ./backend/ /backend/ -RUN ls /backend +ENV PYTHONDONTWRITEBYTECODE 1 +ENV PYTHONUNBUFFERED 1 USER doccano:doccano VOLUME /backend/staticfiles diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml index 11bc0540dc..317c797f0d 100644 --- a/docker/docker-compose.prod.yml +++ b/docker/docker-compose.prod.yml @@ -2,10 +2,7 @@ version: "3.7" services: backend: - build: - context: .. - dockerfile: docker/Dockerfile.prod - image: doccano_backend:prod + image: doccano/doccano:backend volumes: - static_volume:/backend/staticfiles - media:/backend/media @@ -26,10 +23,7 @@ services: - network-frontend celery: - build: - context: .. - dockerfile: docker/Dockerfile.prod - image: doccano_celery:prod + image: doccano/doccano:backend volumes: - media:/backend/media - tmp_file:/backend/filepond-temp-uploads @@ -45,8 +39,25 @@ services: networks: - network-backend + flower: + image: doccano/doccano:backend + entrypoint: ["/opt/bin/prod-flower.sh"] + environment: + PYTHONUNBUFFERED: "1" + CELERY_BROKER_URL: "amqp://${RABBITMQ_DEFAULT_USER}:${RABBITMQ_DEFAULT_PASS}@rabbitmq" + DATABASE_URL: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?sslmode=disable" + DJANGO_SETTINGS_MODULE: "config.settings.production" + FLOWER_BASIC_AUTH: "${FLOWER_BASIC_AUTH}" # Format "username:password" + depends_on: + - celery + ports: + - 5555:5555 + networks: + - network-backend + - network-frontend + rabbitmq: - image: rabbitmq:3.8-alpine + image: rabbitmq:3.10.7-alpine environment: RABBITMQ_DEFAULT_USER: "${RABBITMQ_DEFAULT_USER}" RABBITMQ_DEFAULT_PASS: "${RABBITMQ_DEFAULT_PASS}" @@ -56,13 +67,18 @@ services: - network-backend nginx: - build: - context: .. - dockerfile: docker/Dockerfile.nginx - image: doccano_nginx:prod + image: doccano/doccano:frontend + command: > + /bin/sh -c + "envsubst ' + $${WORKER_PROCESSES} + '< /etc/nginx/nginx.conf.template + > /etc/nginx/nginx.conf + && nginx -g 'daemon off;'" environment: API_URL: "http://backend:8000" GOOGLE_TRACKING_ID: "" + WORKER_PROCESSES: "auto" volumes: - static_volume:/static - media:/media diff --git a/docker/docs_docker-quickstart_Version2.md b/docker/docs_docker-quickstart_Version2.md new file mode 100644 index 0000000000..23141cabcb --- /dev/null +++ b/docker/docs_docker-quickstart_Version2.md @@ -0,0 +1,66 @@ +# Running Doccano with Docker + +This guide explains how to run doccano using Docker and Docker Compose, including the steps needed to ensure export functionality. + +## 1. Clone the Repository + +```bash +git clone https://github.com/doccano/doccano.git +cd doccano +``` + +## 2. Build and Start the Containers + +```bash +docker compose -f docker/docker-compose.yml up --build +``` + +This will start: +- The Django backend +- The frontend UI +- The Celery worker (required for export) +- Redis (for task queue) + +## 3. Access the Web UI + +Open [http://localhost:8000](http://localhost:8000) in your browser. + +## 4. Create a Superuser + +In a new terminal, run: +```bash +docker compose -f docker/docker-compose.yml exec backend python manage.py createsuperuser +``` + +## 5. Use Doccano + +- Log in with your superuser credentials. +- Create a project, import data, annotate, and export. + +## 6. Stopping Doccano + +To stop all services: +```bash +docker compose -f docker/docker-compose.yml down +``` + +--- + +## Troubleshooting + +- **Export not working?** + The Celery worker must be running (it is included in the default Docker Compose setup). + If you see no exported file, check the logs of the `worker` service: + ```bash + docker compose -f docker/docker-compose.yml logs worker + ``` +- **Persistent data:** + By default, the database is stored in a Docker volume for persistence between runs. + +--- + +## References + +- [Django backend (source)](https://github.com/doccano/doccano/tree/master/backend) +- [Frontend (source)](https://github.com/doccano/doccano/tree/master/frontend) +- [Original README](../README.md) diff --git a/docker/nginx/nginx.conf b/docker/nginx/nginx.conf.template similarity index 95% rename from docker/nginx/nginx.conf rename to docker/nginx/nginx.conf.template index cb16cc1622..f3a7155bd7 100644 --- a/docker/nginx/nginx.conf +++ b/docker/nginx/nginx.conf.template @@ -1,4 +1,4 @@ -worker_processes auto; +worker_processes ${WORKER_PROCESSES}; error_log /var/log/nginx/error.log warn; diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 02b77c7f9f..a46f937989 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -51,17 +51,75 @@ Explain the suggestion and include additional details to help developers underst * Specify which version of doccano you're using. * Specify the name and version of the OS you're using. -### Pull Request Process +## development workflow -Please follow these steps to have your contribution considered by the maintainers: +1. **Fork the project & clone it locally:** Click the "Fork" button in the header of the [GitHub repository](https://github.com/doccano/doccano), creating a copy of `doccano` in your GitHub account. To get a working copy on your local machine, you have to clone your fork. Click the "Clone or Download" button in the right-hand side bar, then append its output to the `git clone` command. -1. Open a related issue before making a pull request as much as possible. -2. Follow all instructions in [the template](PULL_REQUEST_TEMPLATE.md) -3. Follow the [styleguides](#styleguides) -4. After you submit your pull request, verify that all [status checks](https://help.github.com/articles/about-status-checks/) are passing
What if the status checks are failing?If a status check is failing, and you believe that the failure is unrelated to your change, please leave a comment on the pull request explaining why you believe the failure is unrelated. A maintainer will re-run the status check for you. If we conclude that the failure was a false positive, then we will open an issue to track that problem with our status check suite.
-5. You may merge the Pull Request in once you have the sign-off of the project members([@Hironsan](https://github.com/Hironsan) or [@icoxfog417](https://github.com/icoxfog417)). + $ git clone https://github.com/YOUR_USERNAME/doccano.git -While the prerequisites above must be satisfied prior to having your pull request reviewed, the reviewer(s) may ask you to complete additional design work, tests, or other changes before your pull request can be ultimately accepted. +1. **Create an upstream remote and sync your local copy:** Connect your local copy to the original "upstream" repository by adding it as a remote. + + $ cd doccano + $ git remote add upstream https://github.com:doccano/doccano.git + + You should now have two remotes: read/write-able `origin` points to your GitHub fork, and a read-only `upstream` points to the original repo. Be sure to [keep your fork in sync](https://help.github.com/en/articles/syncing-a-fork) with the original, reducing the likelihood of merge conflicts later on. + +1. **Create a branch for each piece of work:** Branch off `develop` for each bugfix or feature that you're working on. Give your branch a descriptive, meaningful name like `bugfix-for-issue-1234` or `improve-io-performance`, so others know at a glance what you're working on. + + $ git checkout develop + $ git pull develop master && git push origin develop + $ git checkout -b my-descriptive-branch-name + + At this point, you may want to install your version of `doccano`. It's usually best to do this within a dedicated virtual environment; We recomment to use `poetry` with Python 3.8+: + + $ cd backend + $ poetry install + $ poetry shell + + Second, set up the database and run the development server. Doccano uses Django and Django Rest Framework as a backend. We can set up them by using Django command: + + $ python manage.py migrate + $ python manage.py create_roles + $ python manage.py create_admin --noinput --username "admin" --email "admin@example.com" --password "password" + $ python manage.py runserver + + In another terminal, you need to run Celery in `backend` directory to use import/export dataset feature: + + $ celery --app=config worker --loglevel=INFO --concurrency=1 + + The doccano frontend is built in Node.js and uses Yarn as a package manager. If you haven't installed them yet, please see Node.js and Yarn documentation. + + First, to install the defined dependencies for our project, just run the install command. + + $ cd frontend + $ yarn install + + Then run the dev command to serve with hot reload at : + + $ yarn dev + + Now, you can access to the frontend at . + +1. **Implement your changes:** Use your preferred text editor to modify the `doccano` source code. Be sure to keep your changes focused and in scope, and follow the coding conventions described below! Document your code as you write it. Run your changes against any existing tests and add new ones as needed to validate your changes; make sure you don’t accidentally break existing functionality! Several common commands can be accessed via the Poetry task: + + $ poetry run task mypy + $ poetry run task flake8 + $ poetry run task black + $ poetry run task isort + $ poetry run task test + + For the frontend, you can execute the following commands: + + $ yarn lintfix + $ yarn precommit + $ yarn fix:prettier + +1. **Push commits to your forked repository:** Group changes into atomic git commits, then push them to your `origin` repository. There's no need to wait until all changes are final before pushing — it's always good to have a backup, in case something goes wrong in your local copy. + + $ git push origin my-descriptive-branch-name + +1. **Open a new Pull Request in GitHub:** When you're ready to submit your changes to the main repo, navigate to your forked repository on GitHub. Switch to your working branch then click "New pull request"; alternatively, if you recently pushed, you may see a banner at the top of the repo with a "Compare & pull request" button, which you can click on to initiate the same process. Fill out the PR template completely and clearly, confirm that the code "diff" is as expected, then submit the PR. A number of processes will run automatically via GitHub Workflows (see `.github/workflows/`); we'll want to make sure everything passes before the PR gets merged. +1. **Respond to any code review feedback:** At this point, @Hironsan will review your work and either request additional changes/clarification or approve your work. There may be some necessary back-and-forth; please do your best to be responsive. If you haven’t gotten a response in a week or so, please politely nudge him in the same thread — thanks in advance for your patience! ## Styleguides diff --git a/docs/advanced/auto_labelling_config.md b/docs/advanced/auto_labelling_config.md index ffe8eecad5..6fff33ccc3 100644 --- a/docs/advanced/auto_labelling_config.md +++ b/docs/advanced/auto_labelling_config.md @@ -12,13 +12,15 @@ The tutorial is divided into several sections: In this tutorial, we will show you how to set up auto-labeling using Amazon Comprehend Sentiment Analysis as an example. Therefore, we assume that you have a text classification project in doccano, an AWS account and be able to generate access keys. -## Select a Template +## Use pre-defined service + +### Select a Template First, move to the "settings" page and open "Auto Labeling" tab. The new tab should display a "Create" button and an empty table. Click the button and select "Amazon Comprehend Sentiment Analysis" from the dropdown menu: ![](../images/auto-labeling/select_template.png) -## Set Request Parameters +### Set Request Parameters Next, you need to set parameters to send an API request. In the case of Amazon Comprehend Sentiment Analysis, the following parameters are required: @@ -35,7 +37,7 @@ Then, we will test them using the sample text to make sure whether the parameter ![](../images/auto-labeling/test_parameters.png) -## Specify Response Mapping +### Specify Response Mapping Now, you can successfully fetch the API response. Next, you need to convert it to doccano format(below) with the mapping template([Jinja2](https://jinja.palletsprojects.com/en/2.11.x/) format). @@ -64,7 +66,7 @@ After setting the template, we will test them using the sample response. This re ![](../images/auto-labeling/test_mapping_template.png) -## Specify Label Mapping +### Specify Label Mapping Once you specify the mapping template, you need to convert the label in the response into the one you defined at the label page. @@ -76,10 +78,84 @@ After adding the label mapping, we will test them using the sample response: ![](../images/auto-labeling/test_label_mapping.png) -## Enable the Feature +### Enable the Feature Finally, move to the "annotation" page and click "Auto Labeling" button. It should display a "Slide" button for switching enable/disable auto-labeling feature. Try to enable it: ![](../images/auto-labeling/enable.png) Each time you view a new document, it will be labeled automatically. + +## Use your own API + +First, select "Custom REST Request": + +![](../images/auto-labeling/custom_rest_request_template.png) + +Next, you need to build your own API. Any framework can be used. Here we will use [Flask](https://flask.palletsprojects.com/en/2.2.x/) to create a minimal application. This application always returns the same labelīŧˆ`{"label": "NEG"}`īŧ‰. We also call `get_json` method and output its return value to make sure we can receive the data. + +```bash +from flask import Flask, request + +app = Flask(__name__) + +@app.route("/", methods=["POST"]) +def predict(): + print(request.get_json()) + return {"label": "NEG"} +``` + +Save it as `hello.py` or something similar. Make sure to not call your application `flask.py` because this would conflict with Flask itself. + +To run the application, use the `flask` command. You need to tell the Flask where your application is with the `--app` option. + +```bash +$ flask --app hello run + * Serving Flask app 'hello' + * Debug mode: off + * Running on http://127.0.0.1:5000 +Press CTRL+C to quit +``` + +OK. Let's return to doccano. + +Next, you need to set parameters(`url` and `method`). Let's set the Flask application's URL and method: + +![](../images/auto-labeling/custom_rest_request_parameters.png) + +Next, select the add button next to Body. Enter `text` as key and `{{ text }}` as value. This value is a placeholder and will actually be replaced by your own text. + +![](../images/auto-labeling/custom_rest_request_body.png) + +Then, test the parameters with the sample text. If it is working correctly, it should return `{"label": "NEG"}`. + +![](../images/auto-labeling/custom_rest_request_test_parameters.png) + +You should also see the following in the console: + +```bash +127.0.0.1 - - [13/Sep/2022 15:19:57] "GET / HTTP/1.1" 405 - +{'text': 'This is a test sentence.'} +``` + +Next, convert the response from your API into a format that doccano can handle. We can access the response by the `input` variable. The mapping template looks like the following: + +```bash +[ + { + "label": "{{ input.label }}" + } +] +``` + +Test the mapping template. If it is working correctly, it should be as follows: + +```bash +[ + { + "label": "NEG" + } +] +``` + +The rest is the same as when using a predefined service. diff --git a/docs/developer_guide.md b/docs/developer_guide.md index db02348dea..85652b56e3 100644 --- a/docs/developer_guide.md +++ b/docs/developer_guide.md @@ -1,6 +1,6 @@ # Developer Guide -The important directories are as follows: +The important doccano directories are: ```bash ├── backend/ @@ -11,7 +11,7 @@ The important directories are as follows: ## backend -The `backend/` directory includes the backend's REST API code. These APIs are built by [Python 3.8+](https://www.python.org/) and [Django 4.0+](https://www.djangoproject.com). The all of the packages are managed by Poetry, Python packaging and dependency management software. The directory structure of the backend follows mainly [Django](https://www.djangoproject.com) one. The following table shows the main files and directories: +The `backend/` directory includes the backend's REST API code. These APIs are built by [Python 3.8+](https://www.python.org/) and [Django 4.0+](https://www.djangoproject.com). All of the packages are managed by Poetry, Python packaging, and dependency management software. The directory structure of the backend follows mainly the [Django](https://www.djangoproject.com) structure. The following table shows the main files and directories: | file or directory | description | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -32,8 +32,19 @@ The `backend/` directory includes the backend's REST API code. These APIs are bu | poetry.lock | Related to Poetry. This file prevents you from automatically getting the latest versions of your dependencies. See [Basic usage](https://python-poetry.org/docs/basic-usage/) in Poetry documentation. | | pyproject.toml | This file contains build system requirements and information, which are used by pip to build the package. See [pyproject.toml](https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml/) and [The pyproject.toml file in Poetry](https://python-poetry.org/docs/pyproject/) in detail. | -If you want to setup the backend environment, please see [Installation guide](./install-and-upgrade-doccano.md#install-from-source). +If you want to set up the backend environment, see the [Installation guide](./install_and_upgrade_doccano.md#install-from-source). +Also, you can set the following environment variables: + +| Environment Variable | Description | +| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| SECRET_KEY | A secret key for a particular doccano installation. This is used to provide cryptographic signing, and should be set to a unique, unpredictable value. You should change the fixed default value. See [SECRET_KEY](https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-SECRET_KEY) in detail. | +| DEBUG | A boolean that turns on/off debug mode. If `DEBUG` is `True`, the detailed error message will be shown. The default value is `True`. See [DEBUG](https://docs.djangoproject.com/en/4.1/ref/settings/) in detail. | +| DATABASE_URL | A string to specify the database configuration. The string schema is in line with [dj-database-url](https://github.com/jazzband/dj-database-url). See the page for the detailed information. | +| IMPORT_BATCH_SIZE | A number to specify the batch size for importing dataset. The larger the value, the faster the dataset imports. The default value is `1000`. | +| MAX_UPLOAD_SIZE | A number to specify the max upload file size. The default value is 1073741824(1024^3=1GB). | +| ENABLE_FILE_TYPE_CHECK | A boolean that turns on/off file type check on importing datasets. If `ENABLE_FILE_TYPE_CHECK` is `True`, the MIME types of the files are checked. | +| CELERY_BROKER_URL | A string to point to your broker’s service URL. See [Configuration and defaults](https://docs.celeryq.dev/en/stable/userguide/configuration.html) in detail. | ## docker @@ -57,7 +68,7 @@ On the other hand, the one of the `Dockerfile` is as follows: ## frontend -The `frontend/` directory contains frontend code. The `frontent` directory structure follows [Nuxt.js](https://ru.nuxtjs.org) one. See the [Nuxt.js documentation](https://nuxtjs.org/guide/directory-structure/) in details. +The `frontend/` directory contains frontend code. The `frontend` directory structure follows the [Nuxt.js](https://ru.nuxtjs.org) structure. See the [Nuxt.js documentation](https://nuxtjs.org/guide/directory-structure/) for details. ## tools @@ -68,6 +79,7 @@ The `tools` directory contains some shell scripts. They are mainly used in Docke | create-package.sh | This script creates doccano's Python package. Note that yarn and poetry must already be installed. | | heroku.sh | This script is used to create django's superuser in Heroku. | | prod-celery.sh | This script is used to run celery in `docker-compose.prod.yml`. | +| prod-flower.sh | This script is used to run Flower in `docker-compose.prod.yml`. | | prod-django.sh | This script is used to run gunicorn in `docker-compose.prod.yml`. In addition, create roles, superuser, and migrate. | | run.sh | This script is used in `Dockerfile`. After creating roles and superuser, run gunicorn and celery. | diff --git a/docs/faq.md b/docs/faq.md index 2ed976adfa..d9b031cf5c 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -2,69 +2,63 @@ ## How to create a user -After running doccano webserver, login to the admin site(in the case of pip installation) via . The below is the example of port `8000` and username `admin`. If you set your own port or username and password on running the server, please change to your one. +To create a new doccano user: -![](images/faq/user_creation/login.png) +1. Run the doccano webserver. +2. Log in to the admin site (in the case of pip installation) via . -After login to the admin site, select `Users`: + The example below uses the port `8000` and username `admin`. If you set your own port or username and password on running the server, use those values to log in. + ![](images/faq/user_creation/login.png) +3. After logging in to the admin site, click **Users**: + ![](images/faq/user_creation/select_users.png) +4. Click the **ADD USER** button in the upper right corner: + ![](images/faq/user_creation/select_add_user.png) +5. After entering the username and password for the new user, click **SAVE**: + ![](images/faq/user_creation/create_user.png) -![](images/faq/user_creation/select_users.png) - -Select the ADD USER button in the upper right corner: - -![](images/faq/user_creation/select_add_user.png) - -After entering the username and password for the new user, select the `SAVE` button: - -![](images/faq/user_creation/create_user.png) - -Congratulations. Now you are able to log in to doccano as a new user. After logging out of the admin site, try logging in as a new user. +Congratulations. Now you can log in to doccano as a new user. After logging out of the admin site, try logging in to doccano as a new user. ## How to add a user to your project -Note: This step assumes you have already created a new user. See [How to create a user](#how-to-create-a-user) in detail. - -After logging in to doccano, select your project. Note that you must be the administrator of the project to add users to the project. - -Select `Members` from the left side menu. If you are not the administrator of the project, `Members` will not be displayed. +**Note**: You must be the administrator of the project to add new users to it. These instructions also assume that you have already created a new user. See [How to create a user](#how-to-create-a-user) above. -![](images/faq/add_annotator/select_members.png) +To add a user to your project: -Select the `Add` button to display the form. Fill in this form with the user name and role you want to add to the project. Then, select the `Save` button. +1. Log in to doccano. +2. Click on your project. +3. From the left side menu, click **Members**. If you are not the administrator of the project, **Members** will not appear. + ![](images/faq/add_annotator/select_members.png) +4. Click **Add** and fill in the Add Member form with the user name and role you want to add to the project. +5. Click **Save**. + ![](images/faq/add_annotator/select_user.png) -![](images/faq/add_annotator/select_user.png) - -Congratulations. Now the new user are able to access the project. +Now the new user can access the project. ## How to change the password -After running doccano webserver, login to the admin site(in the case of pip installation) via . Note that you need to have a staff permission to login to the admin site. If you don't have it, please ask the administrator to change your password. - -![](images/faq/user_creation/login.png) - -After login to the admin site, select `Users`: - -![](images/faq/user_creation/select_users.png) - -Select the user you want to change the password: - -![](images/faq/how_to_change_password/user_list.png) - -Click `this form` link: +To change a user's password: -![](images/faq/how_to_change_password/user_page.png) +1. Run the doccano webserver. +2. Log in to the admin site (in the case of pip installation) via . -After showing a form below, change password there: - -![](images/faq/how_to_change_password/change_password.png) + **Note**: You need to have a staff permission to log in to the admin site. If you don't have the right permissions, ask the administrator to change your password. + ![](images/faq/user_creation/login.png) +3. Click **Users**. + ![](images/faq/user_creation/select_users.png) +4. Click on the name of the user whose password you want to change: + ![](images/faq/how_to_change_password/user_list.png) +5. Click the link that says **this form** in the password section. + ![](images/faq/how_to_change_password/user_page.png) +6. Fill out the form and change the password. + ![](images/faq/how_to_change_password/change_password.png) ## I can't upload my data -Please check the following list. +To troubleshoot, review this list: - File encoding: `UTF-8` is appropriate. - Filename: alphabetic file name is suitable. -- File format selection: File format radio button should be selected properly. +- File format selection: file format radio button should be selected properly. - When you are using JSON/JSONL: Confirm JSON data is valid. - You can use [JSONLint](https://jsonlint.com/) or some other tool (when JSONL, pick one data and check it). - When you are using CSV: Confirm CSV data is valid. @@ -72,24 +66,42 @@ Please check the following list. - Lack of line: Data file should not contain blank line. - Lack of field: Data file should not contain blank field. -**You don't need your real & all data to validate file format. The picked data & masked data is suitable if your data is large or secret.** +**You don't need your real complete data to validate the file format. The picked data and masked data is suitable if your data is large or secret.** + +## I want to change the port number -## I want to change port number +In the case of Docker Compose, you can change the port number by editing `docker-compose.prod.yml`. -On production, edit `docker-compose.prod.yml` file: change `80:80` substring in `nginx`/`ports` section to `:80`. +1. Change `80:8080` to `:8080` in `nginx`/`ports` section as follows: -On development, edit `docker-compose.dev.yml` file: change `8000:8000` substring in `backend`/`ports` section to `:8000`. + ```yaml + nginx: + image: doccano/doccano:frontend + ports: + - :8080 + ``` + +2. Add the `CSRF_TRUSTED_ORIGINS` environment variable to the `backend`/`environment` section as follows: + +```yaml + backend: + image: doccano/doccano:backend + environment: + ... + DJANGO_SETTINGS_MODULE: "config.settings.production" + CSRF_TRUSTED_ORIGINS: "http://127.0.0.1:" +``` ## I want to update to the latest doccano image 1. Execute `git pull` to reflect the latest doccano. -2. Delete the volume that `doccano_node_modules`, `doccano_static_volume`, `doccano_venv` and `doccano_www`. - **Do not delete `doccano_postgres_data` because it stores your projects data.** +2. Delete the volume that `doccano_node_modules`, `doccano_static_volume`, `doccano_venv` and `doccano_www`. + **Do not delete `doccano_postgres_data` because it stores your projects data.** 3. Rebuild the doccano image. The following commands are the procedure for 2~3. -``` +```bash ❯ docker volume ls DRIVER VOLUME NAME local doccano_node_modules @@ -100,3 +112,22 @@ local doccano_www ❯ docker volume rm doccano_node_modules doccano_static_volume doccano_venv doccano_www ❯ docker-compose -f docker-compose.prod.yml build --no-cache ``` + +## django.db.utils.OperationalError: no such function: JSON_VALID + +doccano uses JSONField on SQLite. So you need to enable the JSON1 extension on Python's sqlite3 library. If the extension is not enabled on your installation, a system error will be raised. This is especially related to the user who uses macOS and Python which is less than 3.7, Windows and Python which is less than 3.9. + +If you have this problem, try [enabling JSON1 extension on SQLite](https://code.djangoproject.com/wiki/JSON1Extension). + +## CSRF failed + +If you have this problem, set the `CSRF_TRUSTED_ORIGINS` environment variable to your domain name. For example, if your domain name is `example.com`, set `CSRF_TRUSTED_ORIGINS=example.com`. In the debug mode, the default value is `http://127.0.0.1:3000`, `http://0.0.0.0:3000`, and `http://localhost:3000`. If you are using Docker Compose, set `CSRF_TRUSTED_ORIGINS` in `docker-compose.prod.yml`: + +```yaml +backend: + image: doccano/doccano:backend + environment: + ... + DJANGO_SETTINGS_MODULE: "config.settings.production" + CSRF_TRUSTED_ORIGINS: "http://192.168.10.3:3000" +``` diff --git a/docs/images/auto-labeling/custom_rest_request_body.png b/docs/images/auto-labeling/custom_rest_request_body.png new file mode 100644 index 0000000000..f2942c3ba1 Binary files /dev/null and b/docs/images/auto-labeling/custom_rest_request_body.png differ diff --git a/docs/images/auto-labeling/custom_rest_request_parameters.png b/docs/images/auto-labeling/custom_rest_request_parameters.png new file mode 100644 index 0000000000..26ebeeb569 Binary files /dev/null and b/docs/images/auto-labeling/custom_rest_request_parameters.png differ diff --git a/docs/images/auto-labeling/custom_rest_request_template.png b/docs/images/auto-labeling/custom_rest_request_template.png new file mode 100644 index 0000000000..58ec172aff Binary files /dev/null and b/docs/images/auto-labeling/custom_rest_request_template.png differ diff --git a/docs/images/auto-labeling/custom_rest_request_test_parameters.png b/docs/images/auto-labeling/custom_rest_request_test_parameters.png new file mode 100644 index 0000000000..a07ecd9228 Binary files /dev/null and b/docs/images/auto-labeling/custom_rest_request_test_parameters.png differ diff --git a/docs/index.md b/docs/index.md index ab7cbbe822..6e99fb5179 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,49 +2,52 @@ ## What is doccano? -doccano is an open-source data labeling tool for machine learning practitioners. You can perform different types of labeling tasks with many data formats. You can try doccano from the [demo page](http://doccano.herokuapp.com). +**doccano** is an open-source data labeling tool for machine learning practitioners. You can use doccano to perform different types of labeling tasks with many data formats. To see what doccano can do, try the [doccano demo](http://doccano.herokuapp.com). ![Demo image](https://raw.githubusercontent.com/doccano/doccano/master/docs/images/demo/demo.gif) -You can also integrate doccano with your script because it exposes the features as REST APIs. By using the APIs, you can label your data by using some machine learning model. See API documentation in detail. +You can also integrate doccano with your script via the doccano REST APIs. By using the doccano APIs, you can label your data by using some machine learning model. -## Labeling workflow with doccano +## Doccano labeling workflow -Start and finish a labeling project with doccano by the following steps: +To complete a labeling project with doccano: 1. Install doccano. 2. Run doccano. 3. Set up the labeling project. Select the type of labeling project and configure project settings. -4. Import dataset. You can also import labeled datasets. +4. Import your dataset. You can also import labeled datasets. 5. Add users to the project. 6. Define the annotation guideline. 7. Start labeling the data. 8. Export the labeled dataset. -## Quick start +## Quickstart -1. Install doccano: +1. Install doccano with pip (Python 3.8+): -```bash -pip install doccano -``` + ```bash + pip install doccano + ``` 2. Run doccano: -```bash -doccano init -doccano createuser -doccano webserver -# In another terminal, run the following command: -doccano task -``` - -3. Open doccano UI at . -4. Sign up with a username and password created by the `doccano createuser`. -5. Click `Create` to create a project and start labeling data. -6. Click `Import dataset` on the dataset page and import the dataset you want to use. -7. Click `Start annotation` and label the data. -8. Click `Export dataset` on the dataset page and export the labeled dataset. + doccano init + doccano createuser + doccano webserver + # In another terminal, run the command: + doccano task + +3. Open the doccano UI at . +4. Sign in with the username and password created by `doccano createuser`. + + The default is **username:** admin, **password:** password. + +5. Change the default admin password at . +6. Return to the doccano UI at . +7. Create a project for labeling data. Click **Create**, select a project type, and fill out project details. +8. Import a dataset. Go to the **Dataset** page and click **Actions** > **Import Dataset** and import the dataset you want to use. +9. Click **Annotate** and label the data. +10. When you're finished, export the labeled dataset. Go to the **Dataset** page and click **Actions** > **Export dataset**. ## Architecture @@ -56,5 +59,6 @@ You can customize doccano to suit your needs. The architecture of doccano consis | [doccano frontend](https://github.com/doccano/doccano/tree/master/frontend) | Javascript web app using [Vue.js](https://vuejs.org/) and [Nuxt.js](https://nuxtjs.org/) | Perform data labeling in a user interface. | ## Contact +If you get stuck, check the [FAQ](faq.md). -For help and feedback, please feel free to contact [the author](https://github.com/Hironsan). +For help and feedback, feel free to contact [the author](https://github.com/Hironsan). diff --git a/docs/install_and_upgrade_doccano.md b/docs/install_and_upgrade_doccano.md index 6e41195ce6..eb556e5cdc 100644 --- a/docs/install_and_upgrade_doccano.md +++ b/docs/install_and_upgrade_doccano.md @@ -2,12 +2,26 @@ Install doccano on local or in the cloud. Choose the installation method that works best for your environment: -- [Install with pip](#install-with-pip) -- [Install with Docker](#install-with-docker) -- [Install with Docker Compose](#install-with-docker-compose) -- [Install from source](#install-from-source) -- [Install to cloud](#install-to-cloud) -- [Upgrade doccano](#upgrade-doccano) +- [Install doccano](#install-doccano) + - [System requirements](#system-requirements) + - [Web browser support](#web-browser-support) + - [Port requirements](#port-requirements) + - [Install with pip](#install-with-pip) + - [Use PostgreSQL as a database](#use-postgresql-as-a-database) + - [Use RabbitMQ as a message broker](#use-rabbitmq-as-a-message-broker) + - [Use Flower to monitor Celery tasks](#use-flower-to-monitor-celery-tasks) + - [Install with Docker](#install-with-docker) + - [Build a local image with Docker](#build-a-local-image-with-docker) + - [Use Flower](#use-flower) + - [Install with Docker Compose](#install-with-docker-compose) + - [Install from source](#install-from-source) + - [Backend](#backend) + - [Frontend](#frontend) + - [How to create a Python package](#how-to-create-a-python-package) + - [Install to cloud](#install-to-cloud) + - [Upgrade doccano](#upgrade-doccano) + - [After v1.6.0](#after-v160) + - [Before v1.6.0](#before-v160) ## System requirements @@ -54,6 +68,73 @@ doccano task Open . +### Use PostgreSQL as a database + +By default, SQLite 3 is used for the default database system. You can also use other database systems like PostgreSQL, MySQL, and so on. Here we will show you how to use PostgreSQL. + +First, you need to install `psycopg2-binary` as an additional dependency: + +```bash +pip install psycopg2-binary +``` + +Next, set up PostgreSQL. You can set up PostgreSQL directly, but here we will use Docker. Let's run the `docker run` command with the user name(`POSTGRES_USER`), password(`POSTGRES_PASSWORD`), and database name(`POSTGRES_DB`). For other options, please refer to the [official documentation](https://hub.docker.com/_/postgres). + +```bash +docker run -d \ + --name doccano-postgres \ + -e POSTGRES_USER=doccano_admin \ + -e POSTGRES_PASSWORD=doccano_pass \ + -e POSTGRES_DB=doccano \ + -v doccano-db:/var/lib/postgresql/data \ + -p 5432:5432 \ + postgres:13.8-alpine +``` + +Then, set `DATABASE_URL` environment variable according to your PostgreSQL credentials. The schema is in line with dj-database-url. Please refer to the [official documentation](https://github.com/jazzband/dj-database-url) for the detailed information. + +```bash +# export DATABASE_URL="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}?sslmode=disable" +export DATABASE_URL="postgres://doccano_admin:doccano_pass@localhost:5432/doccano?sslmode=disable" +``` + +That's it. Now you can start by running the `doccano init` command. + +### Use RabbitMQ as a message broker + +doccano uses Celery and a message broker to handle long tasks like importing/exporting datasets. By default, SQLite3 is used for the default message broker. You can also use other message brokers like RabbitMQ, Redis, and so on. Here we will show you how to use RabbitMQ. + +First, set up RabbitMQ. You can set up RabbitMQ directly, but here we will use Docker. Let's run the `docker run` command with the user name(`RABBITMQ_DEFAULT_USER`), password(`RABBITMQ_DEFAULT_PASS`). For other options, please refer to the [official documentation](https://hub.docker.com/_/rabbitmq). + +```bash +docker run -d \ + --hostname doccano \ + --name doccano-rabbit \ + -e RABBITMQ_DEFAULT_USER=doccano_rabit \ + -e RABBITMQ_DEFAULT_PASS=doccano_pass \ + -p 5672:5672 \ + rabbitmq:3.10.7-alpine +``` + +Then, set `CELERY_BROKER_URL` environment variable according to your RabbitMQ credentials. If you want to know the schema, please refer to the [official documentation](https://docs.celeryq.dev/en/stable/userguide/configuration.html#broker-settings). + +```bash +# export CELERY_BROKER_URL='amqp://${RABBITMQ_DEFAULT_USER}:${RABBITMQ_DEFAULT_PASS}@localhost:5672//' +export CELERY_BROKER_URL='amqp://doccano_rabit:doccano_pass@localhost:5672//' +``` + +That's it. Now you can start webserver and task queue by running the `doccano webserver` and `doccano task` command. Notice that the both commands needs `DATABASE_URL` and `CELERY_BROKER_URL` environment variables if you would change them. + +### Use Flower to monitor Celery tasks + +If you want to monitor and manage celery tasks, you can use [Flower](https://flower.readthedocs.io/en/latest/index.html). The `–basic_auth` option accepts _user:password_ pairs separated by a comma. If configured, any client trying to access this Flower instance will be prompted to provide the credentials specified in this argument: + +```bash +doccano flower --basic_auth=user1:password1,user2:password2 +``` + +Open . + ## Install with Docker doccano is also available as a [Docker](https://www.docker.com/) container. Make sure you have Docker installed on your machine. @@ -79,6 +160,12 @@ docker container start doccano To stop the container, run `docker container stop doccano -t 5`. All data created in the container persist across restarts. +If you want to use the latest features, please specify `nightly` tag: + +```bash +docker pull doccano/doccano:nightly +``` + ### Build a local image with Docker If you want to build a local image, run: @@ -87,6 +174,20 @@ If you want to build a local image, run: docker build -t doccano:latest . -f docker/Dockerfile ``` +### Use Flower + +Set `FLOWER_BASIC_AUTH` environment variable and open `5555` port. The variable accepts _user:password_ pairs separated by a comma. + +```bash +docker container create --name doccano \ + -e "ADMIN_USERNAME=admin" \ + -e "ADMIN_EMAIL=admin@example.com" \ + -e "ADMIN_PASSWORD=password" \ + -e "FLOWER_BASIC_AUTH=username:password" + -v doccano-db:/data \ + -p 8000:8000 -p 5555:5555 doccano/doccano +``` + ## Install with Docker Compose You need to install Git and to clone the repository: @@ -99,7 +200,11 @@ cd doccano To install and start doccano at , run the following command: ```bash -docker-compose -f docker/docker-compose.prod.yml --env-file .env up +cd docker +cp .env.example .env +# Edit with the editor of your choice, in this example nano is used (ctrl+x, then "y" to save). +nano .env +docker-compose -f docker-compose.prod.yml --env-file .env up ``` You can override the default setting by rewriting the `.env` file. See [./docker/.env.example](https://github.com/doccano/doccano/blob/master/docker/.env.example) in detail. @@ -175,6 +280,15 @@ Then run the `dev` command to serve with hot reload at : yarn dev ``` +After you change the code, don't forget to run +the following commands to ensure code consistency: + +```bash +yarn lintfix +yarn precommit +yarn fix:prettier +``` + ### How to create a Python package During development, you may want to create a Python package and verify it works correctly. In such a case, you can create a package by running the following command in the root directory of your project: diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 6f9f67cff7..31939d2e29 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -1,30 +1,30 @@ # Project information -site_name: 'doccano' -site_description: 'A Text Annotation tool for Humans' -site_author: 'Hiroki Nakayama' -site_url: 'https://doccano.github.io/doccano/' +site_name: "doccano" +site_description: "A Text Annotation tool for Humans" +site_author: "Hiroki Nakayama" +site_url: "https://doccano.github.io/doccano/" docs_dir: . # Repository -repo_name: 'doccano/doccano' -repo_url: 'https://github.com/doccano/doccano' +repo_name: "doccano/doccano" +repo_url: "https://github.com/doccano/doccano" # Copyright -copyright: 'Copyright © 2018 - 2019 Hiroki Nakayama' +copyright: "Copyright © 2018 - 2019 Hiroki Nakayama" theme: - name: 'material' + name: "material" palette: - primary: 'cyan' - accent: 'cyan' + primary: "cyan" + accent: "cyan" show_sidebar: true extra: social: - - icon: 'fontawesome/brands/github' - link: 'https://github.com/Hironsan' - - icon: 'fontawesome/brands/github' - link: 'https://twitter.com/Hironsan13' + - icon: "fontawesome/brands/github" + link: "https://github.com/Hironsan" + - icon: "fontawesome/brands/twitter" + link: "https://twitter.com/Hironsan13" plugins: - same-dir @@ -36,10 +36,10 @@ nav: - Tutorial: tutorial.md - Setup cloud storage: setup_cloud_storage.md - Advanced: - - AWS HTTPS settings: advanced/aws_https_settings.md - - OAuth2 settings: advanced/oauth2_settings.md - - Auto Labeling settings: advanced/auto_labelling_config.md - - Developer Guide: developer_guide.md + - AWS HTTPS settings: advanced/aws_https_settings.md + - OAuth2 settings: advanced/oauth2_settings.md + - Auto labeling settings: advanced/auto_labelling_config.md + - Developer guide: developer_guide.md - FAQ: faq.md - - Code of Conduct: CODE_OF_CONDUCT.md + - Code of conduct: CODE_OF_CONDUCT.md - Roadmap: roadmap.md diff --git a/docs/roadmap.md b/docs/roadmap.md index a334f57d10..596586ee74 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -9,7 +9,7 @@ Doccano is now able to: * Annotate a text classification task. * Annotate a sequence labeling task. * Annotate a sequence to sequence task. -* Deploy on Azure, AWS and Heroku by 1-click. +* Deploy on AWS and Heroku by 1-click. * Deploy anywhere by Docker. * Colaborate with many people. * Upload a labeled file. diff --git a/docs/tutorial.md b/docs/tutorial.md index 70e77ca989..fa4cf543b9 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -1,8 +1,10 @@ # Tutorial +This tutorial demonstrates how to use doccano to complete a named entity recognition annotation task for an example science fiction dataset. + ## Dataset -Here we take named entity recognition annotation task for science fiction to give you a brief tutorial on doccano. Below is a JSON file named `books.json` containing lots of science fictions description with different languages. We need to annotate some entities like person name, book title, date and so on. +Here is a JSON file named `books.json` containing lots of science fiction book descriptions in different languages. We need to annotate some entities like names, book titles, dates, and so on. ```json {"text": "The Hitchhiker's Guide to the Galaxy (sometimes referred to as HG2G, HHGTTGor H2G2) is a comedy science fiction series created by Douglas Adams. Originally a radio comedy broadcast on BBC Radio 4 in 1978, it was later adapted to other formats, including stage shows, novels, comic books, a 1981 TV series, a 1984 video game, and 2005 feature film."} @@ -12,55 +14,65 @@ Here we take named entity recognition annotation task for science fiction to giv ## Create a project -We need to create a new project for this task. Log in with the superuser account. - -![Sign in as a superuser.](./images/tutorial/signin.png) +To start, let's create a new project for this task. -To create your project, make sure you're in the project list page and click `Create` button. As for this tutorial, we name the project as `sequence labeling for books`, write some description, choose the sequence labeling task type. +1. Log in to doccano with the superuser account. + ![Sign in as a superuser.](./images/tutorial/signin.png) +2. To create your project, go to the project list page and click **Create**. +3. Fill out the project details. For this tutorial, name the project `sequence labeling for books`, write a description, and choose the sequence labeling task type. ![Creating a project.](./images/tutorial/create_project.png) ## Import a dataset -After creating a project, we will see the `Dataset` page, and click `Import dataset` button in the `Actions` menu. We should see the following screen: +After creating a project, the **Dataset** page appears. -![Importing a dataset.](./images/tutorial/import_dataset.png) +To import a dataset: -We choose `JSON` and click `Select a file` button. Select `books.json` and it would be loaded automatically. +1. Click **Actions** > **Import Dataset**. You should see the following screen: + ![Importing a dataset.](./images/tutorial/import_dataset.png) +2. Choose **JSON** and click **Select a file**. +3. Click **books.json** and it will load automatically. ## Define labels -Click `Labels` button in the left left side menu to define our labels. We should see the label editor page. In label editor page, you can create labels by specifying label text, shortcut key, background color and text color. +Define the labels to use for your annotation project: -![Defining labels.](./images/tutorial/define_labels.png) +1. Click **Labels** in the left side menu. You should see the label editor page. +2. On the label editor page, create labels by specifying label text, a shortcut key, background color, and text color. For this tutorial, let's create some entities related to science fiction, as shown below. -As for the tutorial, we created some entities related to science fictions. +![Defining labels.](./images/tutorial/define_labels.png) ## Add members -Click `Members` button in the left side menu. If you are not the project administrator, the button won't be displayed. - -![](images/faq/add_annotator/select_members.png) +Members are users who can participate in labeling activities. To add members: -Then, select the `Add` button to display the form. Fill in this form with the user name and role you want to add to the project. Then, select the `Save` button. - -![](images/faq/add_annotator/select_user.png) - -If there is no user to select, please create users(see [FAQ](./faq.md)). +1. Click **Members** in the left side menu. If you are not the project administrator, the button won't appear. + ![](images/faq/add_annotator/select_members.png) +2. Click **Add** to display the Add Member form. + ![](images/faq/add_annotator/select_user.png) +3. Fill in the form with the user name and role you want to add to the project. If there is no user to select, you need to create the user first. See the [FAQ](./faq.md) for instructions. +4. Click **Save**. ## Annotation -Next, we are ready to annotate the texts. Just click the `Start annotation` button in the navigation bar, we can start to annotate the documents. +Next, let's annotate the texts. + +Click **Start annotation** in the navigation bar to start annotating the documents. ![Annotating named entities.](./images/tutorial/annotation.png) ## Export the dataset -After the annotation step, we can download the annotated data. Go to the `Dataset` page and click the `Export dataset` button in the `Action` menu. After selecting an export format, click `Export`. You should see the following screen: +After finishing the annotation step, let's download the annotated data. + +1. Go to the **Dataset** page and click **Action** > **Export Dataset**. +2. Select an export format. For this tutorial choose the JSONL format. +3. Click **Export**. You should see this screen: ![Exporting a dataset.](./images/tutorial/export_dataset.png) -Here we choose JSONL file to download the data by clicking the button. Below is the annotated result for our tutorial project. + Below is the annotated result for this tutorial. `sequence_labeling_for_books.json` @@ -71,4 +83,4 @@ Here we choose JSONL file to download the data by clicking the button. Below is "username": "admin"} ``` -Congratulation! You just mastered how to use doccano for a sequence labeling project. +Congratulations! You just explored how to use doccano for a sequence labeling project. diff --git a/frontend/components/auth/SocialLogin.vue b/frontend/components/auth/SocialLogin.vue new file mode 100644 index 0000000000..dc7c1573ae --- /dev/null +++ b/frontend/components/auth/SocialLogin.vue @@ -0,0 +1,51 @@ + + + diff --git a/frontend/components/comment/Comment.vue b/frontend/components/comment/Comment.vue index 66d9441697..b524db970a 100644 --- a/frontend/components/comment/Comment.vue +++ b/frontend/components/comment/Comment.vue @@ -66,10 +66,12 @@ diff --git a/frontend/components/example/FormResetAssignment.vue b/frontend/components/example/FormResetAssignment.vue new file mode 100644 index 0000000000..e7c43ee374 --- /dev/null +++ b/frontend/components/example/FormResetAssignment.vue @@ -0,0 +1,19 @@ + + + diff --git a/frontend/components/example/ImageList.vue b/frontend/components/example/ImageList.vue index b85e369da2..078290e8ad 100644 --- a/frontend/components/example/ImageList.vue +++ b/frontend/components/example/ImageList.vue @@ -23,15 +23,20 @@ - diff --git a/frontend/components/project/ProjectDescriptionField.vue b/frontend/components/project/ProjectDescriptionField.vue new file mode 100644 index 0000000000..827ee48334 --- /dev/null +++ b/frontend/components/project/ProjectDescriptionField.vue @@ -0,0 +1,32 @@ + + + diff --git a/frontend/components/project/ProjectList.vue b/frontend/components/project/ProjectList.vue index 07379e2179..3d64afa260 100644 --- a/frontend/components/project/ProjectList.vue +++ b/frontend/components/project/ProjectList.vue @@ -34,9 +34,9 @@ {{ item.name }} - diff --git a/frontend/components/tasks/toolbar/forms/FormComment.vue b/frontend/components/tasks/toolbar/forms/FormComment.vue index dfd3af6df7..b4eefc37ba 100644 --- a/frontend/components/tasks/toolbar/forms/FormComment.vue +++ b/frontend/components/tasks/toolbar/forms/FormComment.vue @@ -20,10 +20,11 @@ diff --git a/frontend/layouts/workspace.vue b/frontend/layouts/workspace.vue index 5bab94662b..dae6c610da 100644 --- a/frontend/layouts/workspace.vue +++ b/frontend/layouts/workspace.vue @@ -7,7 +7,7 @@ - + @@ -36,7 +36,7 @@ export default { }, computed: { - ...mapGetters('projects', ['getLink', 'currentProject']) + ...mapGetters('projects', ['currentProject']) }, watch: { @@ -46,7 +46,8 @@ export default { }, async created() { - this.isProjectAdmin = await this.$services.member.isProjectAdmin(this.$route.params.id) + const member = await this.$repositories.member.fetchMyRole(this.$route.params.id) + this.isProjectAdmin = member.isProjectAdmin } } diff --git a/frontend/middleware/check-admin.js b/frontend/middleware/check-admin.js index 29b647e528..b8d521bb93 100644 --- a/frontend/middleware/check-admin.js +++ b/frontend/middleware/check-admin.js @@ -6,11 +6,11 @@ export default _.debounce(async function ({ app, store, route, redirect }) { } catch (e) { redirect('/projects') } - const isProjectAdmin = await app.$services.member.isProjectAdmin(route.params.id) + const member = await app.$repositories.member.fetchMyRole(route.params.id) const projectRoot = app.localePath('/projects/' + route.params.id) const path = route.fullPath.replace(/\/$/g, '') - if (isProjectAdmin || path === projectRoot || path.startsWith(projectRoot + '/dataset')) { + if (member.isProjectAdmin || path === projectRoot || path.startsWith(projectRoot + '/dataset')) { return } diff --git a/frontend/middleware/isProjectAdmin.ts b/frontend/middleware/isProjectAdmin.ts new file mode 100644 index 0000000000..76e8e189df --- /dev/null +++ b/frontend/middleware/isProjectAdmin.ts @@ -0,0 +1,10 @@ +import { NuxtAppOptions } from '@nuxt/types' +import _ from 'lodash' + +export default _.debounce(async ({ app, route, redirect }: NuxtAppOptions) => { + const member = await app.$repositories.member.fetchMyRole(route.params.id) + + if (!member.isProjectAdmin) { + return redirect(app.localePath('/projects/' + route.params.id)) + } +}, 1000) diff --git a/frontend/middleware/setCurrentProject.ts b/frontend/middleware/setCurrentProject.ts new file mode 100644 index 0000000000..b32975ccfb --- /dev/null +++ b/frontend/middleware/setCurrentProject.ts @@ -0,0 +1,13 @@ +import { NuxtAppOptions } from '@nuxt/types' +import _ from 'lodash' + +export default _.debounce(async ({ app, route, redirect }: NuxtAppOptions) => { + const project = app.store.getters['projects/currentProject'] + if (project.id !== route.params.id) { + try { + await app.store.dispatch('projects/setCurrentProject', route.params.id) + } catch (e) { + redirect('/projects') + } + } +}, 1000) diff --git a/frontend/nuxt.config.js b/frontend/nuxt.config.js index 6baf886ad3..5a5e09aee9 100644 --- a/frontend/nuxt.config.js +++ b/frontend/nuxt.config.js @@ -46,6 +46,7 @@ export default { '~/plugins/vue-shortkey.js', '~/plugins/vue-konva.js', '~/plugins/services.ts', + '~/plugins/repositories.ts', '~/plugins/color.ts', '~/plugins/role.ts' ], @@ -104,6 +105,9 @@ export default { // Use a fake value for use at build-time '/v1/': { target: process.env.API_URL || 'http://127.0.0.1:8000' + }, + '/media': { + target: process.env.API_URL || 'http://127.0.0.1:8000' } }, /* diff --git a/frontend/package.json b/frontend/package.json index bc8c1b8ba6..804d7e0757 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,17 +18,17 @@ }, "dependencies": { "@flatten-js/core": "^1.3.4", - "@nuxt/vue-app": "^2.15.7", - "@nuxt/webpack": "^2.15.*", + "@nuxt/vue-app": "^2.16.0", + "@nuxt/webpack": "^2.16.0", "@nuxtjs/axios": "^5.13.6", - "@nuxtjs/composition-api": "^0.25.0", + "@nuxtjs/composition-api": "^0.33.1", "@nuxtjs/proxy": "^2.1.0", "@nuxtjs/vuetify": "^1.*", "@toast-ui/vue-editor": "^2.5.3", "@vuejs-community/vue-filter-date-format": "^1.6.3", "@vuejs-community/vue-filter-date-parse": "^1.1.6", "axios": "^0.21.1", - "chart.js": "^2.*", + "chart.js": "^2", "class-transformer": "^0.5.1", "codemirror": "^5.*", "consola": "^2.15.3", @@ -45,9 +45,9 @@ "ts-loader": "^8.3.0", "tui-editor": "^1.4.10", "uuid": "^8.3.2", - "v-annotator": "0.1.27", + "v-annotator": "0.1.28", "vue": "^2.6.14", - "vue-chartjs": "^3.5.1", + "vue-chartjs": "^3", "vue-filepond": "^6.0.3", "vue-konva": "2", "vue-shortkey": "^3.1.7", @@ -64,13 +64,13 @@ "@babel/eslint-parser": "^7.14.7", "@babel/preset-env": "^7.15.8", "@mdi/js": "^6.5.95", - "@nuxt/types": "^2.15.7", + "@nuxt/types": "^2.16.0", "@nuxt/typescript-build": "^2.1.0", "@nuxtjs/eslint-config": "^6.0.1", "@nuxtjs/eslint-config-typescript": "^6.0.1", "@nuxtjs/eslint-module": "^2.0.0", "@nuxtjs/google-analytics": "^2.4.0", - "@nuxtjs/google-fonts": "^1.3.0", + "@nuxtjs/google-fonts": "^2.0.0", "@types/lodash": "^4.14.171", "@types/uuid": "^8.3.4", "@types/wavesurfer.js": "^5.1.0", @@ -88,15 +88,12 @@ "eslint-plugin-nuxt": "^2.0.0", "eslint-plugin-promise": "5.1.0", "eslint-plugin-vue": "^7.14.0", - "jest": "^27.0.6", - "jest-transform-stub": "^2.0.0", "nodemon": "^2.0.12", "prettier": "^2.3.2", "raw-loader": "^4.0.2", "stylus": "^0.54.8", "stylus-loader": "^4.3.3", - "typescript": "^4.3.5", - "vue-jest": "^3.0.7" + "typescript": "^4.3.5" }, "resolutions": { "node-fetch": "^2.6.7", @@ -104,6 +101,9 @@ "highlight.js": "^10.4.1", "markdown-it": "^12.3.2", "watchpack": "^1.7.5", - "minimist": "npm:minimist-lite@2.2.0" + "minimist": "npm:minimist-lite@2.2.0", + "nuxt-i18n/@babel/traverse": "^7.23.2", + "@nuxtjs/eslint-config/**/@babel/traverse": "^7.23.2", + "@nuxtjs/eslint-config-typescript/**/@babel/traverse": "^7.23.2" } } diff --git a/frontend/pages/auth.vue b/frontend/pages/auth.vue index a223e9d040..f63f725cf0 100644 --- a/frontend/pages/auth.vue +++ b/frontend/pages/auth.vue @@ -5,6 +5,7 @@ + @@ -16,14 +17,16 @@ import Vue from 'vue' import { mapActions } from 'vuex' import FormLogin from '@/components/auth/FormLogin.vue' +import SocialLogin from '@/components/auth/SocialLogin.vue' export default Vue.extend({ components: { - FormLogin + FormLogin, + SocialLogin }, methods: { - ...mapActions('auth', ['authenticateUser']) + ...mapActions('auth', ['authenticateUser', 'fetchSocialLink']) } }) diff --git a/frontend/pages/demo/image-caption/index.vue b/frontend/pages/demo/image-caption/index.vue index d544aac6a8..c22a05b510 100644 --- a/frontend/pages/demo/image-caption/index.vue +++ b/frontend/pages/demo/image-caption/index.vue @@ -63,8 +63,8 @@ diff --git a/frontend/pages/projects/_id/dataset/export.vue b/frontend/pages/projects/_id/dataset/export.vue index c9dffe5e2c..3cd95c3030 100644 --- a/frontend/pages/projects/_id/dataset/export.vue +++ b/frontend/pages/projects/_id/dataset/export.vue @@ -39,11 +39,13 @@ - - diff --git a/frontend/pages/projects/_id/image-classification/index.vue b/frontend/pages/projects/_id/image-classification/index.vue index 3bce0f3484..2edd8a568e 100644 --- a/frontend/pages/projects/_id/image-classification/index.vue +++ b/frontend/pages/projects/_id/image-classification/index.vue @@ -29,7 +29,7 @@ v-if="labelOption === 0" :labels="labels" :annotations="annotations" - :single-label="project.singleClassClassification" + :single-label="project.exclusiveCategories" @add="add" @remove="remove" /> @@ -37,13 +37,13 @@ v-else :labels="labels" :annotations="annotations" - :single-label="project.singleClassClassification" + :single-label="project.exclusiveCategories" @add="add" @remove="remove" /> - + - - diff --git a/frontend/pages/projects/_id/text-classification/index.vue b/frontend/pages/projects/_id/text-classification/index.vue index b8bd49ed23..cddbb212c9 100644 --- a/frontend/pages/projects/_id/text-classification/index.vue +++ b/frontend/pages/projects/_id/text-classification/index.vue @@ -42,19 +42,19 @@