From 1ac4b834a287bd81c670b0a7c52a1d3387d24f92 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 28 Jun 2024 14:28:23 +0000 Subject: [PATCH 001/122] Add change request to Segment --- api/segments/models.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/api/segments/models.py b/api/segments/models.py index 992f37ea7023..3e0312b7e2e0 100644 --- a/api/segments/models.py +++ b/api/segments/models.py @@ -68,6 +68,14 @@ class Segment( null=True, blank=True, ) + + change_request = models.ForeignKey( + "workflows_core.ChangeRequest", + on_delete=models.CASCADE, + null=True, + related_name="segments", + ) + metadata = GenericRelation(Metadata) # Only serves segments that are the canonical version. From d78bc719caab01271f8dbd5f8d696075352bd9c9 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 28 Jun 2024 14:31:07 +0000 Subject: [PATCH 002/122] Add migration for adding change requests to segments --- .../0025_add_change_requests_to_segments.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 api/segments/migrations/0025_add_change_requests_to_segments.py diff --git a/api/segments/migrations/0025_add_change_requests_to_segments.py b/api/segments/migrations/0025_add_change_requests_to_segments.py new file mode 100644 index 000000000000..7e46e6701fdd --- /dev/null +++ b/api/segments/migrations/0025_add_change_requests_to_segments.py @@ -0,0 +1,37 @@ +# Generated by Django 3.2.25 on 2024-06-27 16:23 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("workflows_core", "0009_prevent_cascade_delete_from_user_delete"), + ("segments", "0024_add_timestamps_to_segments"), + ] + + operations = [ + migrations.AddField( + model_name="historicalsegment", + name="change_request", + field=models.ForeignKey( + blank=True, + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + to="workflows_core.changerequest", + ), + ), + migrations.AddField( + model_name="segment", + name="change_request", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="segments", + to="workflows_core.changerequest", + ), + ), + ] From 98c56f4ce041ca53df22c821bc023352f02165c7 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Fri, 28 Jun 2024 17:37:23 +0100 Subject: [PATCH 003/122] chore(build): API test image --- .github/workflows/platform-pull-request.yml | 9 +++++++++ Dockerfile | 17 +++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/.github/workflows/platform-pull-request.yml b/.github/workflows/platform-pull-request.yml index 4d819ceddf30..61102cf687f1 100644 --- a/.github/workflows/platform-pull-request.yml +++ b/.github/workflows/platform-pull-request.yml @@ -66,6 +66,15 @@ jobs: with: require: write + docker-build-api-test: + if: github.event.pull_request.draft == false && needs.check-permissions.outputs.can-write + needs: check-permissions + name: Build API Test Image + uses: ./.github/workflows/.reusable-docker-build.yml + with: + target: api-test + image-name: flagsmith-api-test + docker-build-unified: if: github.event.pull_request.draft == false needs: check-permissions diff --git a/Dockerfile b/Dockerfile index 914ba471d6f1..9c526b2c92fa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,6 +37,9 @@ # * api-runtime [python:slim] # * api-runtime-private [api-runtime] +# - Internal stages +# * api-test [build-python] + # - Target (shippable) stages # * private-cloud-api [api-runtime-private, build-python-private] # * private-cloud-unified [api-runtime-private, build-python-private, build-node-django] @@ -133,6 +136,20 @@ FROM api-runtime as api-runtime-private # Install SAML binary dependency RUN apt-get update && apt-get install -y xmlsec1 && rm -rf /var/lib/apt/lists/* +# - Internal stages +# * api-test [build-python] +FROM build-python AS api-runtime-dev + +RUN make install-packages opts='--with dev' + +WORKDIR /app + +COPY api /app/ + +ENTRYPOINT ["/bin/bash"] + +CMD ["-c 'make test'"] + # - Target (shippable) stages # * private-cloud-api [api-runtime-private, build-python-private] FROM api-runtime-private as private-cloud-api From 4e7421fb1eb30d8a0339327d432ac977f5d30eb7 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Fri, 28 Jun 2024 17:42:15 +0100 Subject: [PATCH 004/122] Also publish flagsmith-api-test for main --- .github/workflows/platform-docker-build-test-publish.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/platform-docker-build-test-publish.yml b/.github/workflows/platform-docker-build-test-publish.yml index 24c3bcc74073..691ada66a830 100644 --- a/.github/workflows/platform-docker-build-test-publish.yml +++ b/.github/workflows/platform-docker-build-test-publish.yml @@ -9,6 +9,13 @@ on: - released jobs: + docker-build-api-test: + name: Build API Test Image + uses: ./.github/workflows/.reusable-docker-build.yml + with: + target: api-test + image-name: flagsmith-api-test + docker-build-api: name: Build API Image uses: ./.github/workflows/.reusable-docker-build.yml From d2fda11d3b289a8f74851be853a3688aa918af03 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Fri, 28 Jun 2024 17:43:05 +0100 Subject: [PATCH 005/122] fix target stage name --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 9c526b2c92fa..4de154a4829d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -138,7 +138,7 @@ RUN apt-get update && apt-get install -y xmlsec1 && rm -rf /var/lib/apt/lists/* # - Internal stages # * api-test [build-python] -FROM build-python AS api-runtime-dev +FROM build-python AS api-test RUN make install-packages opts='--with dev' From c7c3ed0d18a26fc283f6bb1413a2d528910be82e Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Fri, 28 Jun 2024 17:44:54 +0100 Subject: [PATCH 006/122] don't scan test images --- .../platform-docker-build-test-publish.yml | 15 ++++++++------- .github/workflows/platform-pull-request.yml | 19 ++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/.github/workflows/platform-docker-build-test-publish.yml b/.github/workflows/platform-docker-build-test-publish.yml index 691ada66a830..fa1f6030d935 100644 --- a/.github/workflows/platform-docker-build-test-publish.yml +++ b/.github/workflows/platform-docker-build-test-publish.yml @@ -9,13 +9,6 @@ on: - released jobs: - docker-build-api-test: - name: Build API Test Image - uses: ./.github/workflows/.reusable-docker-build.yml - with: - target: api-test - image-name: flagsmith-api-test - docker-build-api: name: Build API Image uses: ./.github/workflows/.reusable-docker-build.yml @@ -57,6 +50,14 @@ jobs: secrets: | github_private_cloud_token=${{ secrets.GH_PRIVATE_ACCESS_TOKEN }} + docker-build-api-test: + name: Build API Test Image + uses: ./.github/workflows/.reusable-docker-build.yml + with: + target: api-test + image-name: flagsmith-api-test + scan: false + docker-build-e2e: name: Build E2E Image uses: ./.github/workflows/.reusable-docker-build.yml diff --git a/.github/workflows/platform-pull-request.yml b/.github/workflows/platform-pull-request.yml index 61102cf687f1..ca57bad81779 100644 --- a/.github/workflows/platform-pull-request.yml +++ b/.github/workflows/platform-pull-request.yml @@ -66,15 +66,6 @@ jobs: with: require: write - docker-build-api-test: - if: github.event.pull_request.draft == false && needs.check-permissions.outputs.can-write - needs: check-permissions - name: Build API Test Image - uses: ./.github/workflows/.reusable-docker-build.yml - with: - target: api-test - image-name: flagsmith-api-test - docker-build-unified: if: github.event.pull_request.draft == false needs: check-permissions @@ -105,6 +96,16 @@ jobs: target: oss-frontend image-name: flagsmith-frontend + docker-build-api-test: + if: github.event.pull_request.draft == false && needs.check-permissions.outputs.can-write + needs: check-permissions + name: Build API Test Image + uses: ./.github/workflows/.reusable-docker-build.yml + with: + target: api-test + image-name: flagsmith-api-test + scan: false + docker-build-e2e: if: github.event.pull_request.draft == false needs: check-permissions From e15c0cc388b3ad1c50849b859d613a28316f797d Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 1 Jul 2024 13:12:15 +0000 Subject: [PATCH 007/122] Add shallow clone --- api/segments/models.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/api/segments/models.py b/api/segments/models.py index 392a0616d222..ee525db2c123 100644 --- a/api/segments/models.py +++ b/api/segments/models.py @@ -139,6 +139,10 @@ def id_exists_in_rules_data(rules_data: typing.List[dict]) -> bool: @hook(BEFORE_CREATE, when="version_of", is_now=None) def set_default_version_to_one_if_new_segment(self): + # Change request segments default to None. + if self.change_request_id: + return + if self.version is None: self.version = 1 @@ -153,6 +157,19 @@ def set_version_of_to_self_if_none(self): self.save() segment_audit_log_helper.unset_skip_audit_log(self.id) + def shallow_clone( + self, + name: str, + description: str, + change_request: None | "ChangeRequest", # noqa: F821 + ) -> "Segment": + cloned_segment = deepcopy(self) + cloned_segment.name = name + cloned_segment.description = description + cloned_segment.change_request = change_request + cloned_segment.save() + return cloned_segment + def deep_clone(self) -> "Segment": cloned_segment = deepcopy(self) cloned_segment.id = None From d9e3a4518c2c2bdd8e9fa87e21bff21199a48ca6 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 1 Jul 2024 13:28:13 +0000 Subject: [PATCH 008/122] Switch to optional due to string issue --- api/segments/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/segments/models.py b/api/segments/models.py index ee525db2c123..d25d3ce3cdec 100644 --- a/api/segments/models.py +++ b/api/segments/models.py @@ -161,7 +161,7 @@ def shallow_clone( self, name: str, description: str, - change_request: None | "ChangeRequest", # noqa: F821 + change_request: typing.Optional["ChangeRequest"], # noqa: F821 ) -> "Segment": cloned_segment = deepcopy(self) cloned_segment.name = name From edd2eeb4318983e2f0815ba0d72720f2e4895dfe Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 17 Jul 2024 14:54:07 +0000 Subject: [PATCH 009/122] Set version to None --- api/segments/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/api/segments/models.py b/api/segments/models.py index d25d3ce3cdec..30f5a6177848 100644 --- a/api/segments/models.py +++ b/api/segments/models.py @@ -167,6 +167,7 @@ def shallow_clone( cloned_segment.name = name cloned_segment.description = description cloned_segment.change_request = change_request + cloned_segment.version = None cloned_segment.save() return cloned_segment From 8e8bccba5dc36cef5171bf08030015ad6a0bdf00 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 17 Jul 2024 15:12:00 +0000 Subject: [PATCH 010/122] Add missing attributes to shallow clone --- api/segments/models.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/segments/models.py b/api/segments/models.py index 30f5a6177848..98ff29ac1eb0 100644 --- a/api/segments/models.py +++ b/api/segments/models.py @@ -164,6 +164,9 @@ def shallow_clone( change_request: typing.Optional["ChangeRequest"], # noqa: F821 ) -> "Segment": cloned_segment = deepcopy(self) + cloned_segment.id = None + cloned_segment.version_of = self + cloned_segment.uuid = uuid.uuid4() cloned_segment.name = name cloned_segment.description = description cloned_segment.change_request = change_request From ab52d25b972225501e3111241bfe8fe317aa7a9f Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 17 Jul 2024 15:33:08 +0000 Subject: [PATCH 011/122] Update Django migration number --- ...s_to_segments.py => 0026_add_change_requests_to_segments.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename api/segments/migrations/{0025_add_change_requests_to_segments.py => 0026_add_change_requests_to_segments.py} (94%) diff --git a/api/segments/migrations/0025_add_change_requests_to_segments.py b/api/segments/migrations/0026_add_change_requests_to_segments.py similarity index 94% rename from api/segments/migrations/0025_add_change_requests_to_segments.py rename to api/segments/migrations/0026_add_change_requests_to_segments.py index 7e46e6701fdd..b84f580787d3 100644 --- a/api/segments/migrations/0025_add_change_requests_to_segments.py +++ b/api/segments/migrations/0026_add_change_requests_to_segments.py @@ -8,7 +8,7 @@ class Migration(migrations.Migration): dependencies = [ ("workflows_core", "0009_prevent_cascade_delete_from_user_delete"), - ("segments", "0024_add_timestamps_to_segments"), + ("segments", "0025_set_default_version_on_segment"), ] operations = [ From b0d5119ba210007c92dba38c210cbab9edc6ba64 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 17 Jul 2024 15:34:57 +0000 Subject: [PATCH 012/122] Revert Dockerfile change --- Dockerfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2828f07cd8ab..b3b95375e5e8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -151,9 +151,7 @@ WORKDIR /app COPY api /app/ -ENTRYPOINT ["/bin/bash"] - -CMD ["-c 'make test'"] +CMD ["make test"] # - Target (shippable) stages # * private-cloud-api [api-runtime-private, build-python-private] From 29b0fd56ed41597bd61730d712c61f7608a51142 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 17 Jul 2024 15:37:33 +0000 Subject: [PATCH 013/122] Remove editor noise --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index b3b95375e5e8..87402d321dbc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,11 +19,11 @@ # Build a SaaS API image: # $ GH_TOKEN=$(gh auth token) docker build -t flagsmith-saas-api:dev --target saas-api \ # --secret="id=sse_pgp_pkey,src=./sse_pgp_pkey.key"\ -# --secret="id=github_private_cloud_token,env=GH_TOKEN" . +# --secret="id=github_private_cloud_token,env=GH_TOKEN" . # Build a Private Cloud Unified image: # $ GH_TOKEN=$(gh auth token) docker build -t flagsmith-private-cloud:dev --target private-cloud-unified \ -# --secret="id=github_private_cloud_token,env=GH_TOKEN" . +# --secret="id=github_private_cloud_token,env=GH_TOKEN" . # Table of Contents # Stages are described as stage-name [dependencies] From 9f93b0a5ff4add0cbc6ad966828bc41c0e485586 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 18 Jul 2024 19:23:08 +0000 Subject: [PATCH 014/122] Attempt using a property instead of the many to many relation --- api/features/workflows/core/models.py | 12 ++++++++++++ api/segments/models.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index 83cfb5e4d33e..0895bb5473e9 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -12,6 +12,7 @@ from django.conf import settings from django.core.mail import send_mail from django.db import models +from django.db.models import QuerySet from django.template.loader import render_to_string from django.utils import timezone from django_lifecycle import ( @@ -49,6 +50,7 @@ if typing.TYPE_CHECKING: from environments.models import Environment from projects.models import Project + from segments.models import Segment from users.models import FFAdminUser logger = logging.getLogger(__name__) @@ -91,6 +93,16 @@ class ChangeRequest( null=True, ) + @property + def segments(self) -> QuerySet["Segment"]: + """ + This property simulates the reverse mapping to segments because + the Segment objects model filters out non-actual segments. + """ + from segments.models import Segment + + return Segment.all_objects.filter(change_request_id=self.id) + def approve(self, user: "FFAdminUser"): if user.id == self.user_id: raise CannotApproveOwnChangeRequest( diff --git a/api/segments/models.py b/api/segments/models.py index 98ff29ac1eb0..ac12df10d318 100644 --- a/api/segments/models.py +++ b/api/segments/models.py @@ -73,7 +73,7 @@ class Segment( "workflows_core.ChangeRequest", on_delete=models.CASCADE, null=True, - related_name="segments", + related_name="+", # Use the "segments" property for change request lookups. ) metadata = GenericRelation(Metadata) From 0583c158378fbd0afb47e64f10cd4748a6fc2da6 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 18 Jul 2024 19:23:59 +0000 Subject: [PATCH 015/122] Create test for segment retrieval --- .../core/test_unit_workflows_models.py | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py index c7fa0febcdc1..a27c57ffbee0 100644 --- a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py +++ b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py @@ -28,6 +28,7 @@ ChangeRequestApproval, ChangeRequestGroupAssignment, ) +from segments.models import Segment from users.models import FFAdminUser now = timezone.now() @@ -731,3 +732,23 @@ def test_committing_change_request_with_environment_feature_versions_creates_pub related_object_type=RelatedObjectType.EF_VERSION.name, log=ENVIRONMENT_FEATURE_VERSION_PUBLISHED_MESSAGE % feature.name, ).exists() + + +def test_retrieving_segments( + change_request: ChangeRequest, +) -> None: + # Given + base_segment = Segment.objects.create( + name="Base Segment", + description="Segment description", + project=change_request.environment.project, + ) + + # When + segment = base_segment.shallow_clone( + name="New Name", description="New description", change_request=change_request + ) + + # Then + assert change_request.segments.count() == 1 + assert change_request.segments.first() == segment From 4f52f28a5d4c1c76ff0ee8306452a8d2aadad776 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 18 Jul 2024 19:29:43 +0000 Subject: [PATCH 016/122] Add migration for relation name change --- .../0027_alter_segment_change_request.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 api/segments/migrations/0027_alter_segment_change_request.py diff --git a/api/segments/migrations/0027_alter_segment_change_request.py b/api/segments/migrations/0027_alter_segment_change_request.py new file mode 100644 index 000000000000..064e2e7cad63 --- /dev/null +++ b/api/segments/migrations/0027_alter_segment_change_request.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.25 on 2024-07-18 19:27 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("workflows_core", "0009_prevent_cascade_delete_from_user_delete"), + ("segments", "0026_add_change_requests_to_segments"), + ] + + operations = [ + migrations.AlterField( + model_name="segment", + name="change_request", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="+", + to="workflows_core.changerequest", + ), + ), + ] From 5d37755dc5e930a5414187ad358441855d9b4b19 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 22 Jul 2024 13:40:12 +0000 Subject: [PATCH 017/122] Update migrations --- .../0026_add_change_requests_to_segments.py | 37 --- .../migrations/0026_make_all_segment.py | 210 ++++++++++++++++++ .../0027_alter_segment_change_request.py | 25 --- 3 files changed, 210 insertions(+), 62 deletions(-) delete mode 100644 api/segments/migrations/0026_add_change_requests_to_segments.py create mode 100644 api/segments/migrations/0026_make_all_segment.py delete mode 100644 api/segments/migrations/0027_alter_segment_change_request.py diff --git a/api/segments/migrations/0026_add_change_requests_to_segments.py b/api/segments/migrations/0026_add_change_requests_to_segments.py deleted file mode 100644 index b84f580787d3..000000000000 --- a/api/segments/migrations/0026_add_change_requests_to_segments.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 3.2.25 on 2024-06-27 16:23 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("workflows_core", "0009_prevent_cascade_delete_from_user_delete"), - ("segments", "0025_set_default_version_on_segment"), - ] - - operations = [ - migrations.AddField( - model_name="historicalsegment", - name="change_request", - field=models.ForeignKey( - blank=True, - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - related_name="+", - to="workflows_core.changerequest", - ), - ), - migrations.AddField( - model_name="segment", - name="change_request", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="segments", - to="workflows_core.changerequest", - ), - ), - ] diff --git a/api/segments/migrations/0026_make_all_segment.py b/api/segments/migrations/0026_make_all_segment.py new file mode 100644 index 000000000000..db94c9d018ef --- /dev/null +++ b/api/segments/migrations/0026_make_all_segment.py @@ -0,0 +1,210 @@ +# Generated by Django 3.2.25 on 2024-07-19 16:03 + +import django.db.models.deletion +import simple_history.models +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("workflows_core", "0009_prevent_cascade_delete_from_user_delete"), + ("contenttypes", "0002_remove_content_type_name"), + ("features", "0064_fix_feature_help_text_typo"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("projects", "0024_add_project_edge_v2_migration_read_capacity_budget"), + ("api_keys", "0003_masterapikey_is_admin"), + ("segments", "0025_set_default_version_on_segment"), + ] + + operations = [ + migrations.AddField( + model_name="historicalsegment", + name="polymorphic_ctype", + field=models.ForeignKey( + blank=True, + db_constraint=False, + editable=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + to="contenttypes.contenttype", + ), + ), + migrations.AddField( + model_name="segment", + name="polymorphic_ctype", + field=models.ForeignKey( + editable=False, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="polymorphic_segments.segment_set+", + to="contenttypes.contenttype", + ), + ), + migrations.CreateModel( + name="HistoricalAllSegment", + fields=[ + ( + "segment_ptr", + models.ForeignKey( + auto_created=True, + blank=True, + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + parent_link=True, + related_name="+", + to="segments.segment", + ), + ), + ( + "id", + models.IntegerField( + auto_created=True, blank=True, db_index=True, verbose_name="ID" + ), + ), + ( + "deleted_at", + models.DateTimeField( + blank=True, + db_index=True, + default=None, + editable=False, + null=True, + ), + ), + ("name", models.CharField(max_length=2000)), + ("description", models.TextField(blank=True, null=True)), + ("version", models.IntegerField(null=True)), + ( + "created_at", + models.DateTimeField(blank=True, editable=False, null=True), + ), + ( + "updated_at", + models.DateTimeField(blank=True, editable=False, null=True), + ), + ("history_id", models.AutoField(primary_key=True, serialize=False)), + ("history_date", models.DateTimeField()), + ("history_change_reason", models.CharField(max_length=100, null=True)), + ( + "history_type", + models.CharField( + choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")], + max_length=1, + ), + ), + ( + "change_request", + models.ForeignKey( + blank=True, + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + to="workflows_core.changerequest", + ), + ), + ( + "feature", + models.ForeignKey( + blank=True, + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + to="features.feature", + ), + ), + ( + "history_user", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "master_api_key", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + to="api_keys.masterapikey", + ), + ), + ( + "polymorphic_ctype", + models.ForeignKey( + blank=True, + db_constraint=False, + editable=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + to="contenttypes.contenttype", + ), + ), + ( + "project", + models.ForeignKey( + blank=True, + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + to="projects.project", + ), + ), + ( + "version_of", + models.ForeignKey( + blank=True, + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + to="segments.segment", + ), + ), + ], + options={ + "verbose_name": "historical all segment", + "ordering": ("-history_date", "-history_id"), + "get_latest_by": "history_date", + }, + bases=(simple_history.models.HistoricalChanges, models.Model), + ), + migrations.CreateModel( + name="AllSegment", + fields=[ + ( + "segment_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="segments.segment", + ), + ), + ( + "change_request", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="all_segments", + to="workflows_core.changerequest", + ), + ), + ], + options={ + "abstract": False, + }, + bases=("segments.segment",), + ), + ] diff --git a/api/segments/migrations/0027_alter_segment_change_request.py b/api/segments/migrations/0027_alter_segment_change_request.py deleted file mode 100644 index 064e2e7cad63..000000000000 --- a/api/segments/migrations/0027_alter_segment_change_request.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 3.2.25 on 2024-07-18 19:27 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("workflows_core", "0009_prevent_cascade_delete_from_user_delete"), - ("segments", "0026_add_change_requests_to_segments"), - ] - - operations = [ - migrations.AlterField( - model_name="segment", - name="change_request", - field=models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="+", - to="workflows_core.changerequest", - ), - ), - ] From 197f7eb5ba72208aacc807a9d7563217fff752d5 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 22 Jul 2024 13:40:36 +0000 Subject: [PATCH 018/122] Add django polymorphic --- api/poetry.lock | 17 +++++++++++++++-- api/pyproject.toml | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index 6fd5bcf53762..af34d938fa1e 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -928,6 +928,20 @@ files = [ {file = "django_ordered_model-3.4.3-py3-none-any.whl", hash = "sha256:5aa58277b81b4ca93fb18caf15069af604bac5c5146d2c29aae56da07a86ef1b"}, ] +[[package]] +name = "django-polymorphic" +version = "3.1.0" +description = "Seamless polymorphic inheritance for Django models" +optional = false +python-versions = "*" +files = [ + {file = "django-polymorphic-3.1.0.tar.gz", hash = "sha256:d6955b5308bf6e41dcb22ba7c96f00b51dfa497a8a5ab1e9c06c7951bf417bf8"}, + {file = "django_polymorphic-3.1.0-py3-none-any.whl", hash = "sha256:08bc4f4f4a773a19b2deced5a56deddd1ef56ebd15207bf4052e2901c25ef57e"}, +] + +[package.dependencies] +Django = ">=2.1" + [[package]] name = "django-python3-ldap" version = "0.15.5" @@ -3363,7 +3377,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -4186,4 +4199,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.11, <3.13" -content-hash = "8950da8b0a6456eabce6f4d62e12a8c0df291099eafced2260188692f5697117" +content-hash = "ef3058efde4a21ca978db1caaaef72bcf95d86136f05505e3e3c799aceecbe1f" diff --git a/api/pyproject.toml b/api/pyproject.toml index 6509e65c0ee3..2adafbdfc8a1 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -169,6 +169,7 @@ pygithub = "2.1.1" hubspot-api-client = "^8.2.1" djangorestframework-dataclasses = "^1.3.1" pyotp = "^2.9.0" +django_polymorphic = "^3.1.0" flagsmith-task-processor = { git = "https://github.com/Flagsmith/flagsmith-task-processor", tag = "v1.0.0" } [tool.poetry.group.auth-controller] From b4af2f32c3b2663984bbc9dac89fac8488c787a2 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 22 Jul 2024 13:40:57 +0000 Subject: [PATCH 019/122] Add polymorphic managers --- api/segments/managers.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/api/segments/managers.py b/api/segments/managers.py index d1f977ca06ed..6f4209be5b84 100644 --- a/api/segments/managers.py +++ b/api/segments/managers.py @@ -1,8 +1,13 @@ from core.models import SoftDeleteExportableManager from django.db.models import F +from polymorphic.models import PolymorphicManager -class SegmentManager(SoftDeleteExportableManager): +class AllSegmentManager(SoftDeleteExportableManager, PolymorphicManager): + pass + + +class SegmentManager(AllSegmentManager): def get_queryset(self): """ Returns only the canonical segments, which will always be From 5d1fc03602e85590ed68f6a7b75f9c09062c6ced Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 22 Jul 2024 13:42:05 +0000 Subject: [PATCH 020/122] Remove segments property --- api/features/workflows/core/models.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index 0895bb5473e9..83cfb5e4d33e 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -12,7 +12,6 @@ from django.conf import settings from django.core.mail import send_mail from django.db import models -from django.db.models import QuerySet from django.template.loader import render_to_string from django.utils import timezone from django_lifecycle import ( @@ -50,7 +49,6 @@ if typing.TYPE_CHECKING: from environments.models import Environment from projects.models import Project - from segments.models import Segment from users.models import FFAdminUser logger = logging.getLogger(__name__) @@ -93,16 +91,6 @@ class ChangeRequest( null=True, ) - @property - def segments(self) -> QuerySet["Segment"]: - """ - This property simulates the reverse mapping to segments because - the Segment objects model filters out non-actual segments. - """ - from segments.models import Segment - - return Segment.all_objects.filter(change_request_id=self.id) - def approve(self, user: "FFAdminUser"): if user.id == self.user_id: raise CannotApproveOwnChangeRequest( From 8ce03abef3a582ba8812ec4621314c64ddd46537 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 22 Jul 2024 13:44:09 +0000 Subject: [PATCH 021/122] Add polymorphic to segments --- api/audit/related_object_type.py | 1 + api/segments/models.py | 55 ++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/api/audit/related_object_type.py b/api/audit/related_object_type.py index 6fab2460890b..791d44195eef 100644 --- a/api/audit/related_object_type.py +++ b/api/audit/related_object_type.py @@ -5,6 +5,7 @@ class RelatedObjectType(enum.Enum): FEATURE = "Feature" FEATURE_STATE = "Feature state" SEGMENT = "Segment" + ALL_SEGMENT = "All segment" ENVIRONMENT = "Environment" CHANGE_REQUEST = "Change request" EDGE_IDENTITY = "Edge Identity" diff --git a/api/segments/models.py b/api/segments/models.py index ac12df10d318..19be915a0401 100644 --- a/api/segments/models.py +++ b/api/segments/models.py @@ -4,7 +4,6 @@ from copy import deepcopy from core.models import ( - SoftDeleteExportableManager, SoftDeleteExportableModel, abstract_base_auditable_model_factory, ) @@ -19,6 +18,7 @@ hook, ) from flag_engine.segments import constants +from polymorphic.models import PolymorphicModel from audit.constants import ( SEGMENT_CREATED_MESSAGE, @@ -31,7 +31,7 @@ from projects.models import Project from .helpers import segment_audit_log_helper -from .managers import SegmentManager +from .managers import AllSegmentManager, SegmentManager logger = logging.getLogger(__name__) @@ -40,6 +40,7 @@ class Segment( LifecycleModelMixin, SoftDeleteExportableModel, abstract_base_auditable_model_factory(["uuid"]), + PolymorphicModel, ): history_record_class_path = "segments.models.HistoricalSegment" related_object_type = RelatedObjectType.SEGMENT @@ -69,13 +70,6 @@ class Segment( blank=True, ) - change_request = models.ForeignKey( - "workflows_core.ChangeRequest", - on_delete=models.CASCADE, - null=True, - related_name="+", # Use the "segments" property for change request lookups. - ) - metadata = GenericRelation(Metadata) created_at = models.DateTimeField(null=True, auto_now_add=True) @@ -85,7 +79,7 @@ class Segment( objects = SegmentManager() # Includes versioned segments. - all_objects = SoftDeleteExportableManager() + all_objects = AllSegmentManager() class Meta: ordering = ("id",) # explicit ordering to prevent pagination warnings @@ -140,8 +134,9 @@ def id_exists_in_rules_data(rules_data: typing.List[dict]) -> bool: @hook(BEFORE_CREATE, when="version_of", is_now=None) def set_default_version_to_one_if_new_segment(self): # Change request segments default to None. - if self.change_request_id: - return + if hasattr(self, "change_request_id"): + if self.change_request_id: + return if self.version is None: self.version = 1 @@ -162,15 +157,18 @@ def shallow_clone( name: str, description: str, change_request: typing.Optional["ChangeRequest"], # noqa: F821 - ) -> "Segment": - cloned_segment = deepcopy(self) - cloned_segment.id = None - cloned_segment.version_of = self - cloned_segment.uuid = uuid.uuid4() - cloned_segment.name = name - cloned_segment.description = description - cloned_segment.change_request = change_request - cloned_segment.version = None + ) -> "AllSegment": + cloned_segment = AllSegment( + version_of=self, + uuid=uuid.uuid4(), + name=name, + description=description, + change_request=change_request, + project=self.project, + feature=self.feature, + version=None, + ) + cloned_segment.history.update() cloned_segment.save() return cloned_segment @@ -214,6 +212,21 @@ def _get_project(self): return self.project +# TODO: Make docstring +class AllSegment(Segment): + history_record_class_path = "segments.models.HistoricalAllSegment" + related_object_type = RelatedObjectType.ALL_SEGMENT + + change_request = models.ForeignKey( + "workflows_core.ChangeRequest", + on_delete=models.CASCADE, + null=True, + related_name="all_segments", + ) + + objects = AllSegmentManager() + + class SegmentRule(SoftDeleteExportableModel): ALL_RULE = "ALL" ANY_RULE = "ANY" From 82d67c619d573efd00abfef36d456b5bf96c7c2b Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 22 Jul 2024 13:44:49 +0000 Subject: [PATCH 022/122] Update test --- .../features/workflows/core/test_unit_workflows_models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py index a27c57ffbee0..69fbf090a253 100644 --- a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py +++ b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py @@ -750,5 +750,5 @@ def test_retrieving_segments( ) # Then - assert change_request.segments.count() == 1 - assert change_request.segments.first() == segment + assert change_request.all_segments.count() == 1 + assert change_request.all_segments.first() == segment From 299ecd9447e7ca05e38664f2191903087ce52295 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Tue, 23 Jul 2024 14:15:46 +0000 Subject: [PATCH 023/122] Create polymorphic managers and models --- api/core/models.py | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/api/core/models.py b/api/core/models.py index b561833b5e51..cc4176cb681c 100644 --- a/api/core/models.py +++ b/api/core/models.py @@ -6,8 +6,13 @@ from django.db.models import Manager from django.forms import model_to_dict from django.http import HttpRequest +from polymorphic.query import PolymorphicModelIterable, PolymorphicQuerySet from simple_history.models import HistoricalRecords, ModelChange -from softdelete.models import SoftDeleteManager, SoftDeleteObject +from softdelete.models import ( + SoftDeleteManager, + SoftDeleteObject, + SoftDeleteQuerySet, +) from audit.related_object_type import RelatedObjectType @@ -20,6 +25,29 @@ logger = logging.getLogger(__name__) +class PolymorphicSoftDeleteQuerySet(SoftDeleteQuerySet, PolymorphicQuerySet): + polymorphic_disabled = False + polymorphic_deferred_loading = (set(), True) + + def __init__(self, *args, **kwargs) -> None: + self._iterable_class = PolymorphicModelIterable + super().__init__(*args, **kwargs) + + +class PolymorphicSoftDeleteManager(SoftDeleteManager): + def get_query_set(self): + qs = super().get_query_set().filter(deleted_at__isnull=True) + if not issubclass(qs.__class__, PolymorphicSoftDeleteQuerySet): + qs.__class__ = PolymorphicSoftDeleteQuerySet + return qs + + def get_queryset(self): + qs = super().get_queryset().filter(deleted_at__isnull=True) + if not issubclass(qs.__class__, PolymorphicSoftDeleteQuerySet): + qs.__class__ = PolymorphicSoftDeleteQuerySet + return qs + + class UUIDNaturalKeyManagerMixin: def get_by_natural_key(self, uuid_: str): logger.debug("Getting model %s by natural key", self.model.__name__) @@ -53,6 +81,21 @@ class Meta: abstract = True +class PolymorphicSoftDeleteExportableManager( + UUIDNaturalKeyManagerMixin, PolymorphicSoftDeleteManager +): + pass + + +class PolymorphicSoftDeleteExportableModel( + SoftDeleteObject, AbstractBaseExportableModel +): + objects = PolymorphicSoftDeleteExportableManager() + + class Meta: + abstract = True + + class _BaseHistoricalModel(models.Model): include_in_audit = True _show_change_details_for_create = False From d1381a745893265eb119164e57f64588c3cdcf33 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Tue, 23 Jul 2024 14:16:24 +0000 Subject: [PATCH 024/122] Use polymorphic manager --- api/segments/managers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/segments/managers.py b/api/segments/managers.py index 6f4209be5b84..66abda6690e7 100644 --- a/api/segments/managers.py +++ b/api/segments/managers.py @@ -1,9 +1,9 @@ -from core.models import SoftDeleteExportableManager +from core.models import PolymorphicSoftDeleteExportableManager from django.db.models import F from polymorphic.models import PolymorphicManager -class AllSegmentManager(SoftDeleteExportableManager, PolymorphicManager): +class AllSegmentManager(PolymorphicSoftDeleteExportableManager, PolymorphicManager): pass From fc10d49d5185e9e6379db283b87bcf66622329e7 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Tue, 23 Jul 2024 14:16:50 +0000 Subject: [PATCH 025/122] Add docstring --- api/segments/models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/segments/models.py b/api/segments/models.py index 19be915a0401..8efaafcff5d9 100644 --- a/api/segments/models.py +++ b/api/segments/models.py @@ -212,8 +212,12 @@ def _get_project(self): return self.project -# TODO: Make docstring class AllSegment(Segment): + """ + This model tracks the relationship to change requests for segments. It's a + polymorphic relation to the Segment class which it inherits from. + """ + history_record_class_path = "segments.models.HistoricalAllSegment" related_object_type = RelatedObjectType.ALL_SEGMENT From 1ad0c6c7bf6646358f2c9786828397822ed5d756 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 8 Aug 2024 14:31:14 +0000 Subject: [PATCH 026/122] Update migration to new plan --- .../0026_add_change_request_to_segments.py | 44 ++++ .../migrations/0026_make_all_segment.py | 210 ------------------ 2 files changed, 44 insertions(+), 210 deletions(-) create mode 100644 api/segments/migrations/0026_add_change_request_to_segments.py delete mode 100644 api/segments/migrations/0026_make_all_segment.py diff --git a/api/segments/migrations/0026_add_change_request_to_segments.py b/api/segments/migrations/0026_add_change_request_to_segments.py new file mode 100644 index 000000000000..bbafb40429bb --- /dev/null +++ b/api/segments/migrations/0026_add_change_request_to_segments.py @@ -0,0 +1,44 @@ +# Generated by Django 3.2.25 on 2024-08-08 14:16 + +import django.db.models.deletion +import django.db.models.manager +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("workflows_core", "0009_prevent_cascade_delete_from_user_delete"), + ("segments", "0025_set_default_version_on_segment"), + ] + + operations = [ + migrations.AlterModelManagers( + name="segment", + managers=[ + ("live_objects", django.db.models.manager.Manager()), + ], + ), + migrations.AddField( + model_name="historicalsegment", + name="change_request", + field=models.ForeignKey( + blank=True, + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + to="workflows_core.changerequest", + ), + ), + migrations.AddField( + model_name="segment", + name="change_request", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="segments", + to="workflows_core.changerequest", + ), + ), + ] diff --git a/api/segments/migrations/0026_make_all_segment.py b/api/segments/migrations/0026_make_all_segment.py deleted file mode 100644 index db94c9d018ef..000000000000 --- a/api/segments/migrations/0026_make_all_segment.py +++ /dev/null @@ -1,210 +0,0 @@ -# Generated by Django 3.2.25 on 2024-07-19 16:03 - -import django.db.models.deletion -import simple_history.models -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("workflows_core", "0009_prevent_cascade_delete_from_user_delete"), - ("contenttypes", "0002_remove_content_type_name"), - ("features", "0064_fix_feature_help_text_typo"), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ("projects", "0024_add_project_edge_v2_migration_read_capacity_budget"), - ("api_keys", "0003_masterapikey_is_admin"), - ("segments", "0025_set_default_version_on_segment"), - ] - - operations = [ - migrations.AddField( - model_name="historicalsegment", - name="polymorphic_ctype", - field=models.ForeignKey( - blank=True, - db_constraint=False, - editable=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - related_name="+", - to="contenttypes.contenttype", - ), - ), - migrations.AddField( - model_name="segment", - name="polymorphic_ctype", - field=models.ForeignKey( - editable=False, - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="polymorphic_segments.segment_set+", - to="contenttypes.contenttype", - ), - ), - migrations.CreateModel( - name="HistoricalAllSegment", - fields=[ - ( - "segment_ptr", - models.ForeignKey( - auto_created=True, - blank=True, - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - parent_link=True, - related_name="+", - to="segments.segment", - ), - ), - ( - "id", - models.IntegerField( - auto_created=True, blank=True, db_index=True, verbose_name="ID" - ), - ), - ( - "deleted_at", - models.DateTimeField( - blank=True, - db_index=True, - default=None, - editable=False, - null=True, - ), - ), - ("name", models.CharField(max_length=2000)), - ("description", models.TextField(blank=True, null=True)), - ("version", models.IntegerField(null=True)), - ( - "created_at", - models.DateTimeField(blank=True, editable=False, null=True), - ), - ( - "updated_at", - models.DateTimeField(blank=True, editable=False, null=True), - ), - ("history_id", models.AutoField(primary_key=True, serialize=False)), - ("history_date", models.DateTimeField()), - ("history_change_reason", models.CharField(max_length=100, null=True)), - ( - "history_type", - models.CharField( - choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")], - max_length=1, - ), - ), - ( - "change_request", - models.ForeignKey( - blank=True, - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - related_name="+", - to="workflows_core.changerequest", - ), - ), - ( - "feature", - models.ForeignKey( - blank=True, - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - related_name="+", - to="features.feature", - ), - ), - ( - "history_user", - models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.SET_NULL, - related_name="+", - to=settings.AUTH_USER_MODEL, - ), - ), - ( - "master_api_key", - models.ForeignKey( - blank=True, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - to="api_keys.masterapikey", - ), - ), - ( - "polymorphic_ctype", - models.ForeignKey( - blank=True, - db_constraint=False, - editable=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - related_name="+", - to="contenttypes.contenttype", - ), - ), - ( - "project", - models.ForeignKey( - blank=True, - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - related_name="+", - to="projects.project", - ), - ), - ( - "version_of", - models.ForeignKey( - blank=True, - db_constraint=False, - null=True, - on_delete=django.db.models.deletion.DO_NOTHING, - related_name="+", - to="segments.segment", - ), - ), - ], - options={ - "verbose_name": "historical all segment", - "ordering": ("-history_date", "-history_id"), - "get_latest_by": "history_date", - }, - bases=(simple_history.models.HistoricalChanges, models.Model), - ), - migrations.CreateModel( - name="AllSegment", - fields=[ - ( - "segment_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="segments.segment", - ), - ), - ( - "change_request", - models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="all_segments", - to="workflows_core.changerequest", - ), - ), - ], - options={ - "abstract": False, - }, - bases=("segments.segment",), - ), - ] From 2a879844c87d7548fae145e229c270de6b2d827e Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 8 Aug 2024 14:33:25 +0000 Subject: [PATCH 027/122] Remove polymorphic concerns from core models --- api/core/models.py | 45 +-------------------------------------------- 1 file changed, 1 insertion(+), 44 deletions(-) diff --git a/api/core/models.py b/api/core/models.py index cc4176cb681c..b561833b5e51 100644 --- a/api/core/models.py +++ b/api/core/models.py @@ -6,13 +6,8 @@ from django.db.models import Manager from django.forms import model_to_dict from django.http import HttpRequest -from polymorphic.query import PolymorphicModelIterable, PolymorphicQuerySet from simple_history.models import HistoricalRecords, ModelChange -from softdelete.models import ( - SoftDeleteManager, - SoftDeleteObject, - SoftDeleteQuerySet, -) +from softdelete.models import SoftDeleteManager, SoftDeleteObject from audit.related_object_type import RelatedObjectType @@ -25,29 +20,6 @@ logger = logging.getLogger(__name__) -class PolymorphicSoftDeleteQuerySet(SoftDeleteQuerySet, PolymorphicQuerySet): - polymorphic_disabled = False - polymorphic_deferred_loading = (set(), True) - - def __init__(self, *args, **kwargs) -> None: - self._iterable_class = PolymorphicModelIterable - super().__init__(*args, **kwargs) - - -class PolymorphicSoftDeleteManager(SoftDeleteManager): - def get_query_set(self): - qs = super().get_query_set().filter(deleted_at__isnull=True) - if not issubclass(qs.__class__, PolymorphicSoftDeleteQuerySet): - qs.__class__ = PolymorphicSoftDeleteQuerySet - return qs - - def get_queryset(self): - qs = super().get_queryset().filter(deleted_at__isnull=True) - if not issubclass(qs.__class__, PolymorphicSoftDeleteQuerySet): - qs.__class__ = PolymorphicSoftDeleteQuerySet - return qs - - class UUIDNaturalKeyManagerMixin: def get_by_natural_key(self, uuid_: str): logger.debug("Getting model %s by natural key", self.model.__name__) @@ -81,21 +53,6 @@ class Meta: abstract = True -class PolymorphicSoftDeleteExportableManager( - UUIDNaturalKeyManagerMixin, PolymorphicSoftDeleteManager -): - pass - - -class PolymorphicSoftDeleteExportableModel( - SoftDeleteObject, AbstractBaseExportableModel -): - objects = PolymorphicSoftDeleteExportableManager() - - class Meta: - abstract = True - - class _BaseHistoricalModel(models.Model): include_in_audit = True _show_change_details_for_create = False From cf2bf1fb0a34cb9b7d60aebebb5b6913b8ff7be2 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 8 Aug 2024 14:34:00 +0000 Subject: [PATCH 028/122] Remove polymorphic concerns from managers and switch to live manager --- api/segments/managers.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/api/segments/managers.py b/api/segments/managers.py index 66abda6690e7..83dadb0ae989 100644 --- a/api/segments/managers.py +++ b/api/segments/managers.py @@ -1,13 +1,8 @@ -from core.models import PolymorphicSoftDeleteExportableManager +from core.models import SoftDeleteManager, UUIDNaturalKeyManagerMixin from django.db.models import F -from polymorphic.models import PolymorphicManager -class AllSegmentManager(PolymorphicSoftDeleteExportableManager, PolymorphicManager): - pass - - -class SegmentManager(AllSegmentManager): +class LiveSegmentManager(UUIDNaturalKeyManagerMixin, SoftDeleteManager): def get_queryset(self): """ Returns only the canonical segments, which will always be From 11eb7060071784d1a318d11db8e36d14cd830350 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 8 Aug 2024 18:24:42 +0000 Subject: [PATCH 029/122] Remove AllSegment model and remove polymorphic concerns --- api/segments/models.py | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/api/segments/models.py b/api/segments/models.py index 8efaafcff5d9..ca8838345fad 100644 --- a/api/segments/models.py +++ b/api/segments/models.py @@ -18,7 +18,6 @@ hook, ) from flag_engine.segments import constants -from polymorphic.models import PolymorphicModel from audit.constants import ( SEGMENT_CREATED_MESSAGE, @@ -31,7 +30,7 @@ from projects.models import Project from .helpers import segment_audit_log_helper -from .managers import AllSegmentManager, SegmentManager +from .managers import LiveSegmentManager, SegmentManager logger = logging.getLogger(__name__) @@ -40,7 +39,6 @@ class Segment( LifecycleModelMixin, SoftDeleteExportableModel, abstract_base_auditable_model_factory(["uuid"]), - PolymorphicModel, ): history_record_class_path = "segments.models.HistoricalSegment" related_object_type = RelatedObjectType.SEGMENT @@ -70,16 +68,22 @@ class Segment( blank=True, ) + change_request = models.ForeignKey( + "workflows_core.ChangeRequest", + on_delete=models.CASCADE, + null=True, + related_name="segments", + ) + metadata = GenericRelation(Metadata) created_at = models.DateTimeField(null=True, auto_now_add=True) updated_at = models.DateTimeField(null=True, auto_now=True) - # Only serves segments that are the canonical version. objects = SegmentManager() - # Includes versioned segments. - all_objects = AllSegmentManager() + # Only serves segments that are the canonical version. + live_objects = LiveSegmentManager() class Meta: ordering = ("id",) # explicit ordering to prevent pagination warnings @@ -157,8 +161,8 @@ def shallow_clone( name: str, description: str, change_request: typing.Optional["ChangeRequest"], # noqa: F821 - ) -> "AllSegment": - cloned_segment = AllSegment( + ) -> "Segment": + cloned_segment = Segment( version_of=self, uuid=uuid.uuid4(), name=name, @@ -212,25 +216,6 @@ def _get_project(self): return self.project -class AllSegment(Segment): - """ - This model tracks the relationship to change requests for segments. It's a - polymorphic relation to the Segment class which it inherits from. - """ - - history_record_class_path = "segments.models.HistoricalAllSegment" - related_object_type = RelatedObjectType.ALL_SEGMENT - - change_request = models.ForeignKey( - "workflows_core.ChangeRequest", - on_delete=models.CASCADE, - null=True, - related_name="all_segments", - ) - - objects = AllSegmentManager() - - class SegmentRule(SoftDeleteExportableModel): ALL_RULE = "ALL" ANY_RULE = "ANY" From 6bcc37e4c101e5e52f301ea988a16d4da74d70cc Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 8 Aug 2024 18:25:13 +0000 Subject: [PATCH 030/122] Add segment manager --- api/segments/managers.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/segments/managers.py b/api/segments/managers.py index 83dadb0ae989..2ade293cbcc1 100644 --- a/api/segments/managers.py +++ b/api/segments/managers.py @@ -2,6 +2,10 @@ from django.db.models import F +class SegmentManager(UUIDNaturalKeyManagerMixin, SoftDeleteManager): + pass + + class LiveSegmentManager(UUIDNaturalKeyManagerMixin, SoftDeleteManager): def get_queryset(self): """ From c3ed2caa4ca548d59e7f1f07eeb6c3afe1e60791 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 8 Aug 2024 18:26:03 +0000 Subject: [PATCH 031/122] Change name to segments --- .../features/workflows/core/test_unit_workflows_models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py index 69fbf090a253..a27c57ffbee0 100644 --- a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py +++ b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py @@ -750,5 +750,5 @@ def test_retrieving_segments( ) # Then - assert change_request.all_segments.count() == 1 - assert change_request.all_segments.first() == segment + assert change_request.segments.count() == 1 + assert change_request.segments.first() == segment From 6e95ee658cd1003dcb7130c5072a9e7a3dc5c648 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 8 Aug 2024 18:26:30 +0000 Subject: [PATCH 032/122] Update manager naming --- api/tests/unit/segments/test_unit_segments_models.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api/tests/unit/segments/test_unit_segments_models.py b/api/tests/unit/segments/test_unit_segments_models.py index 351a2fc7cf90..60ae2750e110 100644 --- a/api/tests/unit/segments/test_unit_segments_models.py +++ b/api/tests/unit/segments/test_unit_segments_models.py @@ -336,10 +336,10 @@ def test_manager_returns_only_highest_version_of_segments( assert segment.version == 3 # When - queryset1 = Segment.objects.filter(id=cloned_segment.id) - queryset2 = Segment.all_objects.filter(id=cloned_segment.id) - queryset3 = Segment.objects.filter(id=segment.id) - queryset4 = Segment.all_objects.filter(id=segment.id) + queryset1 = Segment.live_objects.filter(id=cloned_segment.id) + queryset2 = Segment.objects.filter(id=cloned_segment.id) + queryset3 = Segment.live_objects.filter(id=segment.id) + queryset4 = Segment.objects.filter(id=segment.id) # Then assert not queryset1.exists() From aa7c7711ee6c967a0475135929f8463c8f1f9d7c Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 8 Aug 2024 19:18:49 +0000 Subject: [PATCH 033/122] Create test with model manager returning segments --- .../projects/test_unit_projects_models.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/api/tests/unit/projects/test_unit_projects_models.py b/api/tests/unit/projects/test_unit_projects_models.py index a377fa4bae10..4e8918490ba1 100644 --- a/api/tests/unit/projects/test_unit_projects_models.py +++ b/api/tests/unit/projects/test_unit_projects_models.py @@ -8,6 +8,7 @@ from organisations.models import Organisation from projects.models import EdgeV2MigrationStatus, Project +from segments.models import Segment now = timezone.now() tomorrow = now + timedelta(days=1) @@ -55,6 +56,35 @@ def test_get_segments_from_cache_set_not_called(project, segments, monkeypatch): mock_project_segments_cache.set.assert_not_called() +@pytest.mark.django_db() +def test_get_segments_from_cache_set_to_empty_list( + project: Project, + segment: Segment, + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Given + mock_project_segments_cache = mock.MagicMock() + mock_project_segments_cache.get.return_value = [] + + monkeypatch.setattr( + "projects.models.project_segments_cache", mock_project_segments_cache + ) + + # When + segments = project.get_segments_from_cache() + + # Then + # Since we're calling the live_objects manager in the method, + # only one copy of the segment should be returned, not the + # other versioned copy of the segment. + assert segments.count() == 1 + assert segments.first() == segment + + # And correct calls to cache are made + mock_project_segments_cache.get.assert_called_once_with(project.id) + mock_project_segments_cache.set.assert_called_once() + + @pytest.mark.parametrize( "edge_enabled, expected_enable_dynamo_db_value", ((True, True), (False, False)), From 8569c85172a7b0f2b8584a3e0b36f754da60b0d9 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 8 Aug 2024 19:19:38 +0000 Subject: [PATCH 034/122] Switch to live objects manager --- api/environments/models.py | 2 +- api/projects/models.py | 5 ++++- api/segments/views.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/api/environments/models.py b/api/environments/models.py index dd58ce9fa605..b2895ca8f644 100644 --- a/api/environments/models.py +++ b/api/environments/models.py @@ -344,7 +344,7 @@ def get_segments_from_cache(self) -> typing.List[Segment]: segments = environment_segments_cache.get(self.id) if not segments: segments = list( - Segment.objects.filter( + Segment.live_objects.filter( feature_segments__feature_states__environment=self ).prefetch_related( "rules", diff --git a/api/projects/models.py b/api/projects/models.py index d20c26eea833..a9cae6e62ea1 100644 --- a/api/projects/models.py +++ b/api/projects/models.py @@ -142,19 +142,22 @@ def edge_v2_identity_overrides_migrated(self) -> bool: return self.edge_v2_migration_status == EdgeV2MigrationStatus.COMPLETE def get_segments_from_cache(self): + from segments.models import Segment + segments = project_segments_cache.get(self.id) if not segments: # This is optimised to account for rules nested one levels deep (since we # don't support anything above that from the UI at the moment). Anything # past that will require additional queries / thought on how to optimise. - segments = self.segments.all().prefetch_related( + segments = Segment.live_objects.filter(project=self).prefetch_related( "rules", "rules__conditions", "rules__rules", "rules__rules__conditions", "rules__rules__rules", ) + project_segments_cache.set( self.id, segments, timeout=settings.CACHE_PROJECT_SEGMENTS_SECONDS ) diff --git a/api/segments/views.py b/api/segments/views.py index 566dc9a6c1a1..c1426195aba0 100644 --- a/api/segments/views.py +++ b/api/segments/views.py @@ -39,7 +39,7 @@ def get_queryset(self): ) project = get_object_or_404(permitted_projects, pk=self.kwargs["project_pk"]) - queryset = project.segments.all() + queryset = Segment.live_objects.filter(project=project) if self.action == "list": # TODO: at the moment, the UI only shows the name and description of the segment in the list view. From 398e1abca388dc5c1f948710081423379c183fe3 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 8 Aug 2024 19:19:58 +0000 Subject: [PATCH 035/122] Remove stale comment --- api/segments/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/api/segments/models.py b/api/segments/models.py index ca8838345fad..a690f55a2b09 100644 --- a/api/segments/models.py +++ b/api/segments/models.py @@ -59,7 +59,6 @@ class Segment( # This defaults to 1 for newly created segments. version = models.IntegerField(null=True) - # The related_name is not useful without specifying all_objects as a manager. version_of = models.ForeignKey( "self", on_delete=models.CASCADE, From 8722dae184e6529f30c55deb8bbf7cece44a54ad Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 9 Aug 2024 14:33:02 +0000 Subject: [PATCH 036/122] Remove manager (which is weird, because it's still there... ...but I think this was maybe causing the error earlier with looking up models through the many to one managers) --- .../migrations/0026_add_change_request_to_segments.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/api/segments/migrations/0026_add_change_request_to_segments.py b/api/segments/migrations/0026_add_change_request_to_segments.py index bbafb40429bb..d44e18f83396 100644 --- a/api/segments/migrations/0026_add_change_request_to_segments.py +++ b/api/segments/migrations/0026_add_change_request_to_segments.py @@ -1,7 +1,6 @@ -# Generated by Django 3.2.25 on 2024-08-08 14:16 +# Generated by Django 3.2.25 on 2024-08-09 14:22 import django.db.models.deletion -import django.db.models.manager from django.db import migrations, models @@ -13,12 +12,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.AlterModelManagers( - name="segment", - managers=[ - ("live_objects", django.db.models.manager.Manager()), - ], - ), migrations.AddField( model_name="historicalsegment", name="change_request", From 06f71462204563ae888111396ff78a486db1b9aa Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 12 Aug 2024 13:31:32 +0000 Subject: [PATCH 037/122] Use live_objects manager --- api/util/mappers/engine.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/util/mappers/engine.py b/api/util/mappers/engine.py index 90150206ed17..62b3746192b7 100644 --- a/api/util/mappers/engine.py +++ b/api/util/mappers/engine.py @@ -27,6 +27,7 @@ from environments.constants import IDENTITY_INTEGRATIONS_RELATION_NAMES from features.versioning.models import EnvironmentFeatureVersion +from segments.models import Segment if TYPE_CHECKING: # pragma: no cover from environments.identities.models import Identity, Trait @@ -40,7 +41,7 @@ from integrations.webhook.models import WebhookConfiguration from organisations.models import Organisation from projects.models import Project - from segments.models import Segment, SegmentRule + from segments.models import SegmentRule __all__ = ( @@ -194,7 +195,7 @@ def map_environment_to_engine( organisation: "Organisation" = project.organisation # Read relationships - grab all the data needed from the ORM here. - project_segments: List["Segment"] = project.segments.all() + project_segments: List["Segment"] = Segment.live_objects.filter(project=project) project_segment_rules_by_segment_id: Dict[ int, Iterable["SegmentRule"], From 32e63cb62efee6e32b176da3bcf71727eb759ea2 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 15 Aug 2024 14:43:29 +0000 Subject: [PATCH 038/122] Switch manager --- api/segments/managers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/segments/managers.py b/api/segments/managers.py index 2ade293cbcc1..48f4b6da0eac 100644 --- a/api/segments/managers.py +++ b/api/segments/managers.py @@ -1,12 +1,12 @@ -from core.models import SoftDeleteManager, UUIDNaturalKeyManagerMixin +from core.models import SoftDeleteExportableManager from django.db.models import F -class SegmentManager(UUIDNaturalKeyManagerMixin, SoftDeleteManager): +class SegmentManager(SoftDeleteExportableManager): pass -class LiveSegmentManager(UUIDNaturalKeyManagerMixin, SoftDeleteManager): +class LiveSegmentManager(SoftDeleteExportableManager): def get_queryset(self): """ Returns only the canonical segments, which will always be From 4e037ae6d5732c80510762fc4eab1b7720326db8 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 15 Aug 2024 14:43:57 +0000 Subject: [PATCH 039/122] Remove stale all segment type --- api/audit/related_object_type.py | 1 - 1 file changed, 1 deletion(-) diff --git a/api/audit/related_object_type.py b/api/audit/related_object_type.py index 791d44195eef..6fab2460890b 100644 --- a/api/audit/related_object_type.py +++ b/api/audit/related_object_type.py @@ -5,7 +5,6 @@ class RelatedObjectType(enum.Enum): FEATURE = "Feature" FEATURE_STATE = "Feature state" SEGMENT = "Segment" - ALL_SEGMENT = "All segment" ENVIRONMENT = "Environment" CHANGE_REQUEST = "Change request" EDGE_IDENTITY = "Edge Identity" From cbfa0cc1f1a09b7e48f7999a5a29d55ac00194ff Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 16 Aug 2024 12:47:37 +0000 Subject: [PATCH 040/122] Set Prefect to live_objects Segment manager --- api/environments/managers.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/environments/managers.py b/api/environments/managers.py index fe0e0a4b51df..c170bc44ea28 100644 --- a/api/environments/managers.py +++ b/api/environments/managers.py @@ -3,6 +3,7 @@ from features.models import FeatureSegment, FeatureState from features.multivariate.models import MultivariateFeatureStateValue +from segments.models import Segment class EnvironmentManager(SoftDeleteManager): @@ -21,7 +22,10 @@ def filter_for_document_builder( *extra_select_related or (), ) .prefetch_related( - "project__segments", + Prefetch( + "project__segments", + queryset=Segment.live_objects.all(), + ), "project__segments__rules", "project__segments__rules__rules", "project__segments__rules__conditions", From 3aaa93ea0e31255c71ca4fef313f00f150286ef7 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 16 Aug 2024 12:52:44 +0000 Subject: [PATCH 041/122] Add segment tests for getting environment document --- ...unit_environments_views_sdk_environment.py | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/api/tests/unit/environments/test_unit_environments_views_sdk_environment.py b/api/tests/unit/environments/test_unit_environments_views_sdk_environment.py index c14b976d5bcd..6726b67e3840 100644 --- a/api/tests/unit/environments/test_unit_environments_views_sdk_environment.py +++ b/api/tests/unit/environments/test_unit_environments_views_sdk_environment.py @@ -17,24 +17,27 @@ FeatureStateValue, ) from features.multivariate.models import MultivariateFeatureOption +from projects.models import Project from segments.models import Condition, Segment, SegmentRule if TYPE_CHECKING: from pytest_django import DjangoAssertNumQueries from organisations.models import Organisation - from projects.models import Project def test_get_environment_document( organisation_one: "Organisation", + organisation_two: "Organisation", organisation_one_project_one: "Project", django_assert_num_queries: "DjangoAssertNumQueries", ) -> None: # Given project = organisation_one_project_one + project2 = Project.objects.create( + name="standin_project", organisation=organisation_two + ) - # an environment environment = Environment.objects.create(name="Test Environment", project=project) api_key = EnvironmentAPIKey.objects.create(environment=environment) client = APIClient() @@ -44,6 +47,21 @@ def test_get_environment_document( feature = Feature.objects.create(name="test_feature", project=project) for i in range(10): segment = Segment.objects.create(project=project) + + # Create a shallow clone which should not be returned in the document. + segment.shallow_clone( + name=f"disregarded-clone-{i}", + description=f"some-disregarded-clone-{i}", + change_request=None, + ) + + # Create some other segments to ensure that the segments manager was + # properly set. + Segment.objects.create( + project=project2, + name=f"standin_segment{i}", + description=f"Should not be selected {i}", + ) segment_rule = SegmentRule.objects.create( segment=segment, type=SegmentRule.ALL_RULE ) @@ -114,6 +132,7 @@ def test_get_environment_document( # Then assert response.status_code == status.HTTP_200_OK assert response.json() + assert len(response.data["project"]["segments"]) == 10 assert response.headers[FLAGSMITH_UPDATED_AT_HEADER] == str( environment.updated_at.timestamp() ) From 7be93dc2b9eaea28aa67c8343eeb4bc1f5a67f98 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 16 Aug 2024 12:53:33 +0000 Subject: [PATCH 042/122] Revet to calling project.segments for prefetch functionality and add comment --- api/util/mappers/engine.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/util/mappers/engine.py b/api/util/mappers/engine.py index 62b3746192b7..49e545a87a0b 100644 --- a/api/util/mappers/engine.py +++ b/api/util/mappers/engine.py @@ -195,7 +195,11 @@ def map_environment_to_engine( organisation: "Organisation" = project.organisation # Read relationships - grab all the data needed from the ORM here. - project_segments: List["Segment"] = Segment.live_objects.filter(project=project) + + # Because of the queryset parameter of the calling code's + # Prefetch this queryset will actually load the live_objects + # manager for the Segment lookup. + project_segments: List["Segment"] = project.segments.all() project_segment_rules_by_segment_id: Dict[ int, Iterable["SegmentRule"], From e50499fe3c9dfebcf9e45cb8aef6d1da75c44875 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 19 Aug 2024 13:58:25 +0000 Subject: [PATCH 043/122] Filter project segments to canonical version --- api/util/mappers/engine.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/api/util/mappers/engine.py b/api/util/mappers/engine.py index 49e545a87a0b..5c9cb6faad65 100644 --- a/api/util/mappers/engine.py +++ b/api/util/mappers/engine.py @@ -200,6 +200,12 @@ def map_environment_to_engine( # Prefetch this queryset will actually load the live_objects # manager for the Segment lookup. project_segments: List["Segment"] = project.segments.all() + + # Even though the main calling code filters via a prefetch, + # we still want to gaurd this function in case there are other + # callers in the future. + project_segments = [ps for ps in project_segments if ps.id == ps.version_of_id] + project_segment_rules_by_segment_id: Dict[ int, Iterable["SegmentRule"], From 366ade947f25c7ca95fd58c09bb1f4d360bde63b Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 19 Aug 2024 18:53:27 +0000 Subject: [PATCH 044/122] Switch to objects manager --- api/tests/unit/segments/test_unit_segments_views.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/api/tests/unit/segments/test_unit_segments_views.py b/api/tests/unit/segments/test_unit_segments_views.py index a59d5f39d82d..9b8849013d74 100644 --- a/api/tests/unit/segments/test_unit_segments_views.py +++ b/api/tests/unit/segments/test_unit_segments_views.py @@ -573,7 +573,7 @@ def test_update_segment_versioned_segment( # Before updating the segment confirm pre-existing version count which is # automatically set by the fixture. - assert Segment.all_objects.filter(version_of=segment).count() == 2 + assert Segment.objects.filter(version_of=segment).count() == 2 new_condition_property = "foo2" new_condition_value = "bar" @@ -620,13 +620,11 @@ def test_update_segment_versioned_segment( assert response.status_code == status.HTTP_200_OK # Now verify that a new versioned segment has been set. - assert Segment.all_objects.filter(version_of=segment).count() == 3 + assert Segment.objects.filter(version_of=segment).count() == 3 # Now check the previously versioned segment to match former count of conditions. - versioned_segment = Segment.all_objects.filter( - version_of=segment, version=2 - ).first() + versioned_segment = Segment.objects.filter(version_of=segment, version=2).first() assert versioned_segment != segment assert versioned_segment.rules.count() == 1 versioned_rule = versioned_segment.rules.first() From cc7c753a4f0b2cd2950345d5ee9f8519d21fdb4d Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 19 Aug 2024 19:00:59 +0000 Subject: [PATCH 045/122] Fix test to use default manager --- api/tests/unit/segments/test_unit_segments_views.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/api/tests/unit/segments/test_unit_segments_views.py b/api/tests/unit/segments/test_unit_segments_views.py index 9b8849013d74..2fba0123bc07 100644 --- a/api/tests/unit/segments/test_unit_segments_views.py +++ b/api/tests/unit/segments/test_unit_segments_views.py @@ -655,9 +655,7 @@ def test_update_segment_versioned_segment_with_thrown_exception( rule=nested_rule, property="foo", operator=EQUAL, value="bar" ) - assert ( - segment.version == 2 == Segment.all_objects.filter(version_of=segment).count() - ) + assert segment.version == 2 == Segment.objects.filter(version_of=segment).count() new_condition_property = "foo2" new_condition_value = "bar" @@ -708,9 +706,7 @@ def test_update_segment_versioned_segment_with_thrown_exception( segment.refresh_from_db() # Now verify that the version of the segment has not been changed. - assert ( - segment.version == 2 == Segment.all_objects.filter(version_of=segment).count() - ) + assert segment.version == 2 == Segment.objects.filter(version_of=segment).count() @pytest.mark.parametrize( From bba8d9bd6888d00e4184e5f09b5d5ca18f8fa726 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Tue, 20 Aug 2024 12:31:10 +0000 Subject: [PATCH 046/122] Remove stale change request checking code --- api/segments/models.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/api/segments/models.py b/api/segments/models.py index a690f55a2b09..44f8066b82a0 100644 --- a/api/segments/models.py +++ b/api/segments/models.py @@ -136,11 +136,6 @@ def id_exists_in_rules_data(rules_data: typing.List[dict]) -> bool: @hook(BEFORE_CREATE, when="version_of", is_now=None) def set_default_version_to_one_if_new_segment(self): - # Change request segments default to None. - if hasattr(self, "change_request_id"): - if self.change_request_id: - return - if self.version is None: self.version = 1 From 082b02342b727f734d9d47d7a7f31a6c74694b5f Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Tue, 20 Aug 2024 13:04:03 +0000 Subject: [PATCH 047/122] Trigger build From 84287dffc670ceb350d483538abe7bcde44b03d7 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Tue, 20 Aug 2024 15:36:56 +0000 Subject: [PATCH 048/122] Fix typing --- api/segments/serializers.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/api/segments/serializers.py b/api/segments/serializers.py index 322357038eef..c479c331d33e 100644 --- a/api/segments/serializers.py +++ b/api/segments/serializers.py @@ -81,7 +81,9 @@ def create(self, validated_data): self._update_or_create_metadata(metadata_data, segment=segment) return segment - def update(self, instance: Segment, validated_data: dict[str, typing.Any]) -> None: + def update( + self, instance: Segment, validated_data: dict[str, typing.Any] + ) -> Segment: # use the initial data since we need the ids included to determine which to update & which to create rules_data = self.initial_data.pop("rules", []) metadata_data = validated_data.pop("metadata", []) @@ -105,6 +107,7 @@ def update(self, instance: Segment, validated_data: dict[str, typing.Any]) -> No instance.save() cloned_segment.hard_delete() raise + return response def validate_project_segment_limit(self, project: Project) -> None: From 32214463153a6a6863863b6afb720488c1eb6bd5 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Tue, 20 Aug 2024 15:48:12 +0000 Subject: [PATCH 049/122] Fix typing --- api/segments/serializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/segments/serializers.py b/api/segments/serializers.py index c479c331d33e..e43b1351ff6d 100644 --- a/api/segments/serializers.py +++ b/api/segments/serializers.py @@ -213,8 +213,8 @@ def _update_or_create_metadata( @staticmethod def _update_or_create_segment_rule( - rule_data: dict, segment: Segment = None, rule: SegmentRule = None - ) -> typing.Optional[SegmentRule]: + rule_data: dict, segment: None | Segment = None, rule: None | SegmentRule = None + ) -> None | SegmentRule: rule_id = rule_data.pop("id", None) if rule_data.get("delete"): SegmentRule.objects.filter(id=rule_id).delete() From ef295d091e8cdb4443f650399486fc1f2737b70a Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Tue, 27 Aug 2024 15:12:03 +0000 Subject: [PATCH 050/122] Trigger build From f6566033cd3252090328471e23c78cc53f649627 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 28 Aug 2024 18:13:21 +0000 Subject: [PATCH 051/122] Add publishing segments to change requests --- api/features/workflows/core/models.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index cd26ccc000aa..c10fe3b73822 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -112,6 +112,7 @@ def commit(self, committed_by: "FFAdminUser"): self._publish_feature_states() self._publish_environment_feature_versions(committed_by) self._publish_change_sets(committed_by) + self._publish_segments() self.committed_at = timezone.now() self.committed_by = committed_by @@ -179,6 +180,30 @@ def _publish_change_sets(self, published_by: "FFAdminUser") -> None: for change_set in self.change_sets.all(): change_set.publish(user=published_by) + def _publish_segments(self) -> None: + segments = list(self.segments.all()) + if not segments: + return + + for segment in segments: + target_segment = segment.version_of + assert target_segment != segment + + # Deep clone the segment to establish historical version. + target_segment.deep_clone() + + # Set the properties of the change request's segment to the properties + # of the target (i.e., canonical) segment. + target_segment.name = segment.name + target_segment.description = segment.description + target_segment.feature = segment.feature + target_segment.save() + + # Delete the rules in order to replace them with copies of the segment. + target_segment.rules.all().delete() + for rule in segment.rules.all(): + rule.deep_clone(target_segment) + def get_create_log_message(self, history_instance) -> typing.Optional[str]: return CHANGE_REQUEST_CREATED_MESSAGE % self.title From ed4f12dfeac115fccf8c35778695e8b130e571e6 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 28 Aug 2024 18:13:55 +0000 Subject: [PATCH 052/122] Add test for publishing segments --- .../core/test_unit_workflows_models.py | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py index c4eda36b4425..6513b52944a3 100644 --- a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py +++ b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py @@ -5,6 +5,7 @@ import pytest from django.contrib.sites.models import Site from django.utils import timezone +from flag_engine.segments.constants import EQUAL, PERCENTAGE_SPLIT from pytest_mock import MockerFixture from audit.constants import ( @@ -33,7 +34,7 @@ ChangeRequestApproval, ChangeRequestGroupAssignment, ) -from segments.models import Segment +from segments.models import Condition, Segment, SegmentRule from users.models import FFAdminUser now = timezone.now() @@ -794,3 +795,61 @@ def test_change_request_live_from_for_change_request_with_change_set( # Then assert change_request.live_from == now + + +def test_publishing_segments_as_part_of_commit( + segment: Segment, + change_request: ChangeRequest, +) -> None: + # Given + assert segment.version == 2 + cr_segment = segment.shallow_clone("Test Name", "Test Description", change_request) + assert cr_segment.rules.count() == 0 + + # Add some rules that the original segment will be cloning from + parent_rule = SegmentRule.objects.create( + segment=cr_segment, type=SegmentRule.ALL_RULE + ) + + child_rule1 = SegmentRule.objects.create( + rule=parent_rule, type=SegmentRule.ANY_RULE + ) + child_rule2 = SegmentRule.objects.create( + rule=parent_rule, type=SegmentRule.NONE_RULE + ) + Condition.objects.create( + rule=child_rule1, + property="child_rule1", + operator=EQUAL, + value="condition1", + created_with_segment=True, + ) + Condition.objects.create( + rule=child_rule2, + property="child_rule2", + operator=PERCENTAGE_SPLIT, + value="0.2", + created_with_segment=False, + ) + + # When + change_request._publish_segments() + + # Then + segment.refresh_from_db() + assert segment.version == 3 + assert segment.name == "Test Name" + assert segment.description == "Test Description" + assert segment.rules.count() == 1 + parent_rule2 = segment.rules.first() + assert parent_rule2.type == SegmentRule.ALL_RULE + assert parent_rule2.rules.count() == 2 + child_rule3, child_rule4 = list(parent_rule2.rules.all()) + assert child_rule3.type == SegmentRule.ANY_RULE + assert child_rule4.type == SegmentRule.NONE_RULE + assert child_rule3.conditions.count() == 1 + assert child_rule4.conditions.count() == 1 + condition1 = child_rule3.conditions.first() + condition2 = child_rule4.conditions.first() + assert condition1.value == "condition1" + assert condition2.value == "0.2" From a8e0bee9f9c019402ce13b3cbf7bb8619b4abcb0 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 6 Sep 2024 10:35:23 -0400 Subject: [PATCH 053/122] Fix spelling of guard Co-authored-by: Matthew Elwell --- api/util/mappers/engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/util/mappers/engine.py b/api/util/mappers/engine.py index 5c9cb6faad65..2f7a76293837 100644 --- a/api/util/mappers/engine.py +++ b/api/util/mappers/engine.py @@ -202,7 +202,7 @@ def map_environment_to_engine( project_segments: List["Segment"] = project.segments.all() # Even though the main calling code filters via a prefetch, - # we still want to gaurd this function in case there are other + # we still want to guard this function in case there are other # callers in the future. project_segments = [ps for ps in project_segments if ps.id == ps.version_of_id] From a126336e88f9f10ba9f69c848cb85e9b7336a5e8 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 6 Sep 2024 15:41:38 +0000 Subject: [PATCH 054/122] Create get_project_segments_from_cache function --- api/projects/services.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 api/projects/services.py diff --git a/api/projects/services.py b/api/projects/services.py new file mode 100644 index 000000000000..f69414101df5 --- /dev/null +++ b/api/projects/services.py @@ -0,0 +1,35 @@ +import typing + +from django.apps import apps +from django.conf import settings +from django.core.cache import caches + +if typing.TYPE_CHECKING: + from django.db.models import QuerySet + + from segments.models import Segment + +project_segments_cache = caches[settings.PROJECT_SEGMENTS_CACHE_LOCATION] + + +def get_project_segments_from_cache(project_id: int) -> "QuerySet[Segment]": + Segment = apps.get_model("segments", "Segment") + + segments = project_segments_cache.get(project_id) + if not segments: + # This is optimised to account for rules nested one levels deep (since we + # don't support anything above that from the UI at the moment). Anything + # past that will require additional queries / thought on how to optimise. + segments = Segment.live_objects.filter(project_id=project_id).prefetch_related( + "rules", + "rules__conditions", + "rules__rules", + "rules__rules__conditions", + "rules__rules__rules", + ) + + project_segments_cache.set( + project_id, segments, timeout=settings.CACHE_PROJECT_SEGMENTS_SECONDS + ) + + return segments From aaa5d7a85244b64a3cdc1fad9d58983244b4a5ad Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 6 Sep 2024 15:42:06 +0000 Subject: [PATCH 055/122] Set blank to True --- api/segments/migrations/0026_add_change_request_to_segments.py | 3 ++- api/segments/models.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/api/segments/migrations/0026_add_change_request_to_segments.py b/api/segments/migrations/0026_add_change_request_to_segments.py index d44e18f83396..04c51be17e20 100644 --- a/api/segments/migrations/0026_add_change_request_to_segments.py +++ b/api/segments/migrations/0026_add_change_request_to_segments.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.25 on 2024-08-09 14:22 +# Generated by Django 4.2.15 on 2024-09-06 15:36 import django.db.models.deletion from django.db import migrations, models @@ -28,6 +28,7 @@ class Migration(migrations.Migration): model_name="segment", name="change_request", field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name="segments", diff --git a/api/segments/models.py b/api/segments/models.py index 44f8066b82a0..e48cfaab4d10 100644 --- a/api/segments/models.py +++ b/api/segments/models.py @@ -71,6 +71,7 @@ class Segment( "workflows_core.ChangeRequest", on_delete=models.CASCADE, null=True, + blank=True, related_name="segments", ) From a18ad86e0fc90e2e043ab82914aecf6673b068ec Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 6 Sep 2024 15:42:34 +0000 Subject: [PATCH 056/122] Move code to a function --- api/projects/models.py | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/api/projects/models.py b/api/projects/models.py index a9cae6e62ea1..eae1764332b4 100644 --- a/api/projects/models.py +++ b/api/projects/models.py @@ -25,13 +25,13 @@ PermissionModel, ) from projects.managers import ProjectManager +from projects.services import get_project_segments_from_cache from projects.tasks import ( handle_cascade_delete, migrate_project_environments_to_v2, write_environments_to_dynamodb, ) -project_segments_cache = caches[settings.PROJECT_SEGMENTS_CACHE_LOCATION] environment_cache = caches[settings.ENVIRONMENT_CACHE_NAME] @@ -142,27 +142,7 @@ def edge_v2_identity_overrides_migrated(self) -> bool: return self.edge_v2_migration_status == EdgeV2MigrationStatus.COMPLETE def get_segments_from_cache(self): - from segments.models import Segment - - segments = project_segments_cache.get(self.id) - - if not segments: - # This is optimised to account for rules nested one levels deep (since we - # don't support anything above that from the UI at the moment). Anything - # past that will require additional queries / thought on how to optimise. - segments = Segment.live_objects.filter(project=self).prefetch_related( - "rules", - "rules__conditions", - "rules__rules", - "rules__rules__conditions", - "rules__rules__rules", - ) - - project_segments_cache.set( - self.id, segments, timeout=settings.CACHE_PROJECT_SEGMENTS_SECONDS - ) - - return segments + return get_project_segments_from_cache(self.id) @hook(BEFORE_CREATE) def set_enable_dynamo_db(self): From 4fb41766aebcfa4e28986db6b68094c5274660dd Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 6 Sep 2024 15:42:58 +0000 Subject: [PATCH 057/122] Update mock --- api/tests/unit/projects/test_unit_projects_models.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/api/tests/unit/projects/test_unit_projects_models.py b/api/tests/unit/projects/test_unit_projects_models.py index 4e8918490ba1..6448e190e864 100644 --- a/api/tests/unit/projects/test_unit_projects_models.py +++ b/api/tests/unit/projects/test_unit_projects_models.py @@ -22,7 +22,7 @@ def test_get_segments_from_cache(project, monkeypatch): mock_project_segments_cache.get.return_value = None monkeypatch.setattr( - "projects.models.project_segments_cache", mock_project_segments_cache + "projects.services.project_segments_cache", mock_project_segments_cache ) # When @@ -42,7 +42,7 @@ def test_get_segments_from_cache_set_not_called(project, segments, monkeypatch): mock_project_segments_cache.get.return_value = project.segments.all() monkeypatch.setattr( - "projects.models.project_segments_cache", mock_project_segments_cache + "projects.services.project_segments_cache", mock_project_segments_cache ) # When @@ -56,7 +56,6 @@ def test_get_segments_from_cache_set_not_called(project, segments, monkeypatch): mock_project_segments_cache.set.assert_not_called() -@pytest.mark.django_db() def test_get_segments_from_cache_set_to_empty_list( project: Project, segment: Segment, @@ -67,7 +66,7 @@ def test_get_segments_from_cache_set_to_empty_list( mock_project_segments_cache.get.return_value = [] monkeypatch.setattr( - "projects.models.project_segments_cache", mock_project_segments_cache + "projects.services.project_segments_cache", mock_project_segments_cache ) # When From 6c0429d07a8b7ed3634c45c4ff20f4531fbedbbd Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 6 Sep 2024 15:43:18 +0000 Subject: [PATCH 058/122] Test change request commit instead of private method --- .../unit/features/workflows/core/test_unit_workflows_models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py index 6513b52944a3..5c1992d4cd1d 100644 --- a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py +++ b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py @@ -800,6 +800,7 @@ def test_change_request_live_from_for_change_request_with_change_set( def test_publishing_segments_as_part_of_commit( segment: Segment, change_request: ChangeRequest, + admin_user: FFAdminUser, ) -> None: # Given assert segment.version == 2 @@ -833,7 +834,7 @@ def test_publishing_segments_as_part_of_commit( ) # When - change_request._publish_segments() + change_request.commit(admin_user) # Then segment.refresh_from_db() From b2661564f7b183b6b725ed6173f9a1a7e51b7468 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 6 Sep 2024 15:43:47 +0000 Subject: [PATCH 059/122] Skip early return --- api/features/workflows/core/models.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index c10fe3b73822..3c611389faf6 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -181,11 +181,7 @@ def _publish_change_sets(self, published_by: "FFAdminUser") -> None: change_set.publish(user=published_by) def _publish_segments(self) -> None: - segments = list(self.segments.all()) - if not segments: - return - - for segment in segments: + for segment in self.segments.all(): target_segment = segment.version_of assert target_segment != segment From daee2c606676c23fb14b0a2ebff44c67a1327972 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 18 Sep 2024 13:43:12 +0000 Subject: [PATCH 060/122] Add project to change request via migration --- .../0011_add_project_to_change_requests.py | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 api/features/workflows/core/migrations/0011_add_project_to_change_requests.py diff --git a/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py b/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py new file mode 100644 index 000000000000..023c7e5494b6 --- /dev/null +++ b/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py @@ -0,0 +1,62 @@ +# Generated by Django 4.2.15 on 2024-09-17 15:34 + +import django.db.models.deletion +from django.db import migrations, models + + +def set_project_for_existing_environments(apps, schema_model): + ChangeRequest = apps.get_model("workflows_core", "ChangeRequest") + + for change_request in ChangeRequest.objects.filter( + environment_id__isnull=False + ).select_related("environment"): + change_request.project = change_request.environment.project + change_request.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ("environments", "0035_add_use_identity_overrides_in_local_eval"), + ("projects", "0025_add_change_request_project_permissions"), + ("workflows_core", "0010_add_ignore_conflicts_option"), + ] + + operations = [ + migrations.AddField( + model_name="changerequest", + name="project", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="change_requests", + to="projects.project", + ), + ), + migrations.AddField( + model_name="historicalchangerequest", + name="project", + field=models.ForeignKey( + blank=True, + db_constraint=False, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + related_name="+", + to="projects.project", + ), + ), + migrations.AlterField( + model_name="changerequest", + name="environment", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="change_requests", + to="environments.environment", + ), + ), + migrations.RunPython( + set_project_for_existing_environments, + reverse_code=migrations.RunPython.noop, + ), + ] From 5d02c150cd2ea636d86cc6857ae30b4b4f7f33ca Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 18 Sep 2024 13:43:45 +0000 Subject: [PATCH 061/122] Add project permissions for project level change requests via migration --- ..._add_change_request_project_permissions.py | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 api/projects/migrations/0025_add_change_request_project_permissions.py diff --git a/api/projects/migrations/0025_add_change_request_project_permissions.py b/api/projects/migrations/0025_add_change_request_project_permissions.py new file mode 100644 index 000000000000..92f05d493d58 --- /dev/null +++ b/api/projects/migrations/0025_add_change_request_project_permissions.py @@ -0,0 +1,55 @@ +# Generated by Django 4.2.15 on 2024-09-17 14:07 + +from django.db import migrations + +from permissions.models import PROJECT_PERMISSION_TYPE +from projects.permissions import ( + APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS, + MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS, + PROJECT_PERMISSIONS, +) + + +def remove_default_project_permissions(apps, schema_model): + PermissionModel = apps.get_model("permissions", "PermissionModel") + PermissionModel.objects.get(key=MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS).delete() + PermissionModel.objects.get(key=APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS).delete() + + +def insert_default_project_permissions(apps, schema_model): + PermissionModel = apps.get_model("permissions", "PermissionModel") + manage_description = approve_description = None + + for project_permission in PROJECT_PERMISSIONS: + if project_permission[0] == MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS: + manage_description = project_permission[1] + elif project_permission[0] == APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS: + approve_description = project_permission[1] + + assert manage_description + assert approve_description + + PermissionModel.objects.get_or_create( + key=MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS, + description=manage_description, + type=PROJECT_PERMISSION_TYPE, + ) + PermissionModel.objects.get_or_create( + key=APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS, + description=approve_description, + type=PROJECT_PERMISSION_TYPE, + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ("projects", "0024_add_project_edge_v2_migration_read_capacity_budget"), + ] + + operations = [ + migrations.RunPython( + insert_default_project_permissions, + reverse_code=remove_default_project_permissions, + ), + ] From de188436190ddf36ed5f7de49b223a06e5019b01 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 18 Sep 2024 13:44:20 +0000 Subject: [PATCH 062/122] Add test for deleting a change request via task --- .../workflows/core/test_unit_workflows_tasks.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 api/tests/unit/features/workflows/core/test_unit_workflows_tasks.py diff --git a/api/tests/unit/features/workflows/core/test_unit_workflows_tasks.py b/api/tests/unit/features/workflows/core/test_unit_workflows_tasks.py new file mode 100644 index 000000000000..9a98566f5db0 --- /dev/null +++ b/api/tests/unit/features/workflows/core/test_unit_workflows_tasks.py @@ -0,0 +1,14 @@ +from features.workflows.core.models import ChangeRequest +from features.workflows.core.tasks import delete_change_request + + +def test_delete_change_request(change_request: ChangeRequest) -> None: + # Given + assert change_request.deleted_at is None + + # When + delete_change_request(change_request_id=change_request.id) + + # Then + change_request.refresh_from_db() + assert change_request.deleted_at is not None From e123371faecafdfdd24dacca9ba8b2abc6f9d90f Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 18 Sep 2024 13:45:21 +0000 Subject: [PATCH 063/122] Create delete change request task --- api/features/workflows/core/tasks.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 api/features/workflows/core/tasks.py diff --git a/api/features/workflows/core/tasks.py b/api/features/workflows/core/tasks.py new file mode 100644 index 000000000000..26b3f1708da1 --- /dev/null +++ b/api/features/workflows/core/tasks.py @@ -0,0 +1,8 @@ +from task_processor.decorators import register_task_handler + +from features.workflows.core.models import ChangeRequest + + +@register_task_handler() +def delete_change_request(change_request_id: int) -> None: + ChangeRequest.objects.get(pk=change_request_id).delete() From 703776f8558f9be711e97470a3d4f2378dd8db51 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 18 Sep 2024 13:45:56 +0000 Subject: [PATCH 064/122] Add delete change request to project delete task --- api/projects/tasks.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/projects/tasks.py b/api/projects/tasks.py index bbf54fa5b333..031400e775cc 100644 --- a/api/projects/tasks.py +++ b/api/projects/tasks.py @@ -42,6 +42,7 @@ def handle_cascade_delete(project_id: int) -> None: from environments.tasks import delete_environment from features.tasks import delete_feature + from features.workflows.core.tasks import delete_change_request from projects.models import Project from segments.tasks import delete_segment @@ -55,3 +56,6 @@ def handle_cascade_delete(project_id: int) -> None: for feature_id in project.features.values_list("id", flat=True): delete_feature.delay(kwargs={"feature_id": feature_id}) + + for change_request_id in project.change_requests.values_list("id", flat=True): + delete_change_request.delay(kwargs={"change_request_id": change_request_id}) From 64d241bc5d3751ecc468bb2513854b49daa96c9c Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 18 Sep 2024 13:48:24 +0000 Subject: [PATCH 065/122] Reorder task --- api/projects/tasks.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/projects/tasks.py b/api/projects/tasks.py index 031400e775cc..713be8ec67ad 100644 --- a/api/projects/tasks.py +++ b/api/projects/tasks.py @@ -48,6 +48,9 @@ def handle_cascade_delete(project_id: int) -> None: project = Project.objects.all_with_deleted().get(id=project_id) + for change_request_id in project.change_requests.values_list("id", flat=True): + delete_change_request.delay(kwargs={"change_request_id": change_request_id}) + for environment_id in project.environments.values_list("id", flat=True): delete_environment.delay(kwargs={"environment_id": environment_id}) @@ -56,6 +59,3 @@ def handle_cascade_delete(project_id: int) -> None: for feature_id in project.features.values_list("id", flat=True): delete_feature.delay(kwargs={"feature_id": feature_id}) - - for change_request_id in project.change_requests.values_list("id", flat=True): - delete_change_request.delay(kwargs={"change_request_id": change_request_id}) From 06c138f83735cbc55b276bcaeb0e31611d269ad5 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 18 Sep 2024 13:49:00 +0000 Subject: [PATCH 066/122] Add project level permissions for change requests --- api/projects/permissions.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/api/projects/permissions.py b/api/projects/permissions.py index a6fb98f042ea..5fb002e56aa8 100644 --- a/api/projects/permissions.py +++ b/api/projects/permissions.py @@ -18,6 +18,10 @@ EDIT_FEATURE = "EDIT_FEATURE" MANAGE_SEGMENTS = "MANAGE_SEGMENTS" +# Note that this does not impact change requests in an environment +MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS = "MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS" +APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS = "APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS" + TAG_SUPPORTED_PERMISSIONS = [DELETE_FEATURE] PROJECT_PERMISSIONS = [ @@ -28,6 +32,14 @@ (EDIT_FEATURE, "Ability to edit features in the given project."), (MANAGE_SEGMENTS, "Ability to manage segments in the given project."), (VIEW_AUDIT_LOG, "Allows the user to view the audit logs for this organisation."), + ( + MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS, + "Ability to manage change requests associated with a project.", + ), + ( + APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS, + "Ability to approve project level change requests.", + ), ] From b36b730c01b7ad6a3deac3e242f38602aeeea043 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 18 Sep 2024 13:49:26 +0000 Subject: [PATCH 067/122] Add project to change request and set environment to nullable --- api/features/workflows/core/models.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index 248b5be87250..4953db28655c 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -77,10 +77,19 @@ class ChangeRequest( null=True, ) + # Change requests get deleted in a delegated task when a project is deleted. + project = models.ForeignKey( + "projects.Project", + on_delete=models.SET_NULL, + related_name="change_requests", + null=True, + ) + environment = models.ForeignKey( "environments.Environment", on_delete=models.CASCADE, related_name="change_requests", + null=True, ) committed_at = models.DateTimeField(null=True) From ec71d35a3634cadfdcfd104a1beba6d9cf16b144 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 18 Sep 2024 14:22:17 +0000 Subject: [PATCH 068/122] Update comment --- api/features/workflows/core/models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index 4953db28655c..e6fe62f43dca 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -196,7 +196,11 @@ def _publish_segments(self) -> None: target_segment = segment.version_of assert target_segment != segment - # Deep clone the segment to establish historical version. + # Deep clone the segment to establish historical version this is required + # because the target segment will be altered when the segment is published. + # Think of it like a regular update to a segment where we create the clone + # to create the version, then modifying the new 'draft' version with the + # data from the change request. target_segment.deep_clone() # Set the properties of the change request's segment to the properties From c65dc1bbbe03f8b3518bf029f4c0f970788b09bb Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 18 Sep 2024 15:23:21 +0000 Subject: [PATCH 069/122] Add project change request viewset to urls.py --- api/app/urls.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/api/app/urls.py b/api/app/urls.py index 65caa58df8ba..240f5db5f928 100644 --- a/api/app/urls.py +++ b/api/app/urls.py @@ -4,6 +4,7 @@ from django.contrib import admin from django.urls import include, path, re_path from django.views.generic.base import TemplateView +from rest_framework_nested import routers from users.views import password_reset_redirect @@ -54,8 +55,16 @@ if settings.WORKFLOWS_LOGIC_INSTALLED: workflow_views = importlib.import_module("workflows_logic.views") + router = routers.DefaultRouter() + router.register( + "projects//change-requests", + workflow_views.ProjectChangeRequestViewSet, + basename="project-change-requests", + ) + urlpatterns.extend( [ + path("api/v1/", include(router.urls)), path("api/v1/features/workflows/", include("workflows_logic.urls")), path( "api/v1/environments//create-change-request/", From 6b9626dd2275be0e580ce53820c31d46734601db Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 19 Sep 2024 14:15:23 +0000 Subject: [PATCH 070/122] Attempt nested router --- api/app/urls.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/api/app/urls.py b/api/app/urls.py index 240f5db5f928..a8f963aa25cf 100644 --- a/api/app/urls.py +++ b/api/app/urls.py @@ -55,16 +55,21 @@ if settings.WORKFLOWS_LOGIC_INSTALLED: workflow_views = importlib.import_module("workflows_logic.views") + from project.views import ProjectViewSet + router = routers.DefaultRouter() - router.register( - "projects//change-requests", + router.register(r"", ProjectViewSet, basename="project") + + project_router = routers.NestedSimpleRouter(router, r"projects", lookup="project") + project_router.register( + r"change-requests", workflow_views.ProjectChangeRequestViewSet, basename="project-change-requests", ) urlpatterns.extend( [ - path("api/v1/", include(router.urls)), + path("api/v1/", include(project_router.urls)), path("api/v1/features/workflows/", include("workflows_logic.urls")), path( "api/v1/environments//create-change-request/", From ae44b79f9cc5ab42ffdf950bc70c556d7962bc46 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 19 Sep 2024 14:23:37 +0000 Subject: [PATCH 071/122] Fix projects --- api/app/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/app/urls.py b/api/app/urls.py index a8f963aa25cf..6c191f497803 100644 --- a/api/app/urls.py +++ b/api/app/urls.py @@ -55,7 +55,7 @@ if settings.WORKFLOWS_LOGIC_INSTALLED: workflow_views = importlib.import_module("workflows_logic.views") - from project.views import ProjectViewSet + from projects.views import ProjectViewSet router = routers.DefaultRouter() router.register(r"", ProjectViewSet, basename="project") From 8d85fe103142b976ae3e992b5559e0ce11d54fcf Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 19 Sep 2024 14:55:16 +0000 Subject: [PATCH 072/122] Try projects --- api/app/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/app/urls.py b/api/app/urls.py index 6c191f497803..421bcc97b201 100644 --- a/api/app/urls.py +++ b/api/app/urls.py @@ -58,7 +58,7 @@ from projects.views import ProjectViewSet router = routers.DefaultRouter() - router.register(r"", ProjectViewSet, basename="project") + router.register(r"projects", ProjectViewSet, basename="project") project_router = routers.NestedSimpleRouter(router, r"projects", lookup="project") project_router.register( From b65065fedc34771c070dd867ce0031541fa063aa Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 19 Sep 2024 15:01:39 +0000 Subject: [PATCH 073/122] Try including the router --- api/app/urls.py | 1 + 1 file changed, 1 insertion(+) diff --git a/api/app/urls.py b/api/app/urls.py index 421bcc97b201..43f55a3137ad 100644 --- a/api/app/urls.py +++ b/api/app/urls.py @@ -69,6 +69,7 @@ urlpatterns.extend( [ + path("api/v1/", include(router.urls)), path("api/v1/", include(project_router.urls)), path("api/v1/features/workflows/", include("workflows_logic.urls")), path( From 88e1104e9759f9db11b932be2c3bd9e0fef64b24 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 19 Sep 2024 15:53:15 +0000 Subject: [PATCH 074/122] Fix project lookup --- api/features/workflows/core/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index e6fe62f43dca..e8aa2f5ae0dd 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -243,7 +243,7 @@ def _get_environment(self) -> typing.Optional["Environment"]: return self.environment def _get_project(self) -> typing.Optional["Project"]: - return self.environment.project + return self.project or self.environment.project def is_approved(self): return self.environment.minimum_change_request_approvals is None or ( From ab25f93c259d21bea4a31de8d0081ab4f31be77d Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 19 Sep 2024 15:56:00 +0000 Subject: [PATCH 075/122] Check for environment --- api/features/workflows/core/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index e8aa2f5ae0dd..7221ccd67b09 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -243,7 +243,7 @@ def _get_environment(self) -> typing.Optional["Environment"]: return self.environment def _get_project(self) -> typing.Optional["Project"]: - return self.project or self.environment.project + return self.project or (self.environment and self.environment.project) def is_approved(self): return self.environment.minimum_change_request_approvals is None or ( From 508f0aa12c067580607e46f3a29451555de158c1 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 20 Sep 2024 14:14:25 +0000 Subject: [PATCH 076/122] Update url generation code for missing environments --- api/features/workflows/core/models.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index 7221ccd67b09..7fdc7047f63b 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -262,8 +262,13 @@ def url(self): "Change request must be saved before it has a url attribute." ) url = get_current_site_url() - url += f"/project/{self.environment.project_id}" - url += f"/environment/{self.environment.api_key}" + if self.environment: + url += f"/project/{self.environment.project_id}" + url += f"/environment/{self.environment.api_key}" + elif self.project_id: + url += f"/projects/{self.project_id}" + else: + raise RuntimeError("Change request missing fields for URL") url += f"/change-requests/{self.id}" return url From a7a7377e0a98fb756b3e3065893f9e6b1a2d9a56 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 20 Sep 2024 14:31:13 +0000 Subject: [PATCH 077/122] Add minimum_change_request_approvals to project --- ...hange_request_approval_limit_to_projects.py | 18 ++++++++++++++++++ api/projects/models.py | 1 + 2 files changed, 19 insertions(+) create mode 100644 api/projects/migrations/0026_add_change_request_approval_limit_to_projects.py diff --git a/api/projects/migrations/0026_add_change_request_approval_limit_to_projects.py b/api/projects/migrations/0026_add_change_request_approval_limit_to_projects.py new file mode 100644 index 000000000000..209e6d1f5519 --- /dev/null +++ b/api/projects/migrations/0026_add_change_request_approval_limit_to_projects.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.15 on 2024-09-20 14:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("projects", "0025_add_change_request_project_permissions"), + ] + + operations = [ + migrations.AddField( + model_name="project", + name="minimum_change_request_approvals", + field=models.IntegerField(blank=True, null=True), + ), + ] diff --git a/api/projects/models.py b/api/projects/models.py index eae1764332b4..d63a9980c181 100644 --- a/api/projects/models.py +++ b/api/projects/models.py @@ -106,6 +106,7 @@ class Project(LifecycleModelMixin, SoftDeleteExportableModel): default=30, help_text="Number of days without modification in any environment before a flag is considered stale.", ) + minimum_change_request_approvals = models.IntegerField(blank=True, null=True) objects = ProjectManager() From 086a1e273888f580af121ade55b8b381000a86cc Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 20 Sep 2024 14:32:39 +0000 Subject: [PATCH 078/122] Add project related methods --- api/features/workflows/core/models.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index 7fdc7047f63b..198e9fc571e7 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -246,6 +246,21 @@ def _get_project(self) -> typing.Optional["Project"]: return self.project or (self.environment and self.environment.project) def is_approved(self): + if self.environment: + return self.is_approved_via_environment() + if self.project: + return self.is_approved_via_project() + raise RuntimeError( + "Unable to approve change request without environment or project" + ) + + def is_approved_via_project(self): + return self.project.minimum_change_request_approvals is None or ( + self.approvals.filter(approved_at__isnull=False).count() + >= self.project.minimum_change_request_approvals + ) + + def is_approved_via_environment(self): return self.environment.minimum_change_request_approvals is None or ( self.approvals.filter(approved_at__isnull=False).count() >= self.environment.minimum_change_request_approvals @@ -407,6 +422,9 @@ def get_audit_log_author(self, history_instance) -> "FFAdminUser": def _get_environment(self): return self.change_request.environment + def _get_project(self): + return self.change_request._get_project() + class ChangeRequestGroupAssignment(AbstractBaseExportableModel, LifecycleModel): change_request = models.ForeignKey( From b34b8222bab6248d3b268418b4daa2fdc7bb3e72 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 25 Sep 2024 13:55:58 +0000 Subject: [PATCH 079/122] Update permission list count --- api/tests/unit/projects/test_unit_projects_views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/tests/unit/projects/test_unit_projects_views.py b/api/tests/unit/projects/test_unit_projects_views.py index 8a313dffba14..27122924f600 100644 --- a/api/tests/unit/projects/test_unit_projects_views.py +++ b/api/tests/unit/projects/test_unit_projects_views.py @@ -152,7 +152,7 @@ def test_can_list_project_permission(client, project): # Then assert response.status_code == status.HTTP_200_OK assert ( - len(response.json()) == 6 + len(response.json()) == 8 ) # hard code how many permissions we expect there to be From 0316fb8c583fb6b47f42711185e4a7ceee1043f0 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 25 Sep 2024 14:57:51 +0000 Subject: [PATCH 080/122] Add change request to successful delete --- api/tests/unit/projects/test_unit_projects_tasks.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/tests/unit/projects/test_unit_projects_tasks.py b/api/tests/unit/projects/test_unit_projects_tasks.py index cc29d43dbd97..af1aa8f79912 100644 --- a/api/tests/unit/projects/test_unit_projects_tasks.py +++ b/api/tests/unit/projects/test_unit_projects_tasks.py @@ -11,6 +11,7 @@ ) from environments.models import Environment from features.models import Feature +from features.workflows.core.models import ChangeRequest from projects.models import EdgeV2MigrationStatus, Project from projects.tasks import ( handle_cascade_delete, @@ -141,6 +142,7 @@ def test_handle_cascade_delete( feature: Feature, segment: Segment, settings: SettingsWrapper, + project_change_request: ChangeRequest, ) -> None: # Given settings.TASK_RUN_METHOD = TaskRunMethod.SYNCHRONOUSLY @@ -152,3 +154,4 @@ def test_handle_cascade_delete( assert not Environment.objects.filter(id=environment.id).exists() assert not Feature.objects.filter(id=feature.id).exists() assert not Segment.objects.filter(id=segment.id).exists() + assert not ChangeRequest.objects.filter(id=project_change_request.id).exists() From 3e30460b4920662677880a74f0682c84b79056e8 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 25 Sep 2024 14:58:18 +0000 Subject: [PATCH 081/122] Add unit tests for change requests --- .../core/test_unit_workflows_models.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py index b6946d074057..1441c4ea3307 100644 --- a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py +++ b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py @@ -3,6 +3,7 @@ import freezegun import pytest +from core.helpers import get_current_site_url from django.contrib.sites.models import Site from django.db.models import Q from django.utils import timezone @@ -976,3 +977,31 @@ def _create_segment(percentage_value: int) -> Segment: ) assert len(after_cr_1_flags) == 1 assert after_cr_1_flags[0].feature_segment.segment == twenty_percent_segment + + +def test_approval_via_project(project_change_request: ChangeRequest) -> None: + # Given - The project change request fixture + assert project_change_request.environment is None + assert project_change_request.project.minimum_change_request_approvals is None + + # When + is_approved = project_change_request.is_approved() + + # Then + assert is_approved is True + + +def test_url_via_project(project_change_request: ChangeRequest) -> None: + # Given + assert project_change_request.environment is None + + # When + url = project_change_request.url + + # Then + project_id = project_change_request.project.id + expected_url = get_current_site_url() + expected_url += ( + f"/projects/{project_id}/change-requests/{project_change_request.id}" + ) + assert url == expected_url From b5e86cdfeeed9b775277afb1b454cf3a71471045 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 25 Sep 2024 14:58:44 +0000 Subject: [PATCH 082/122] Add pragma: no cover since this is a migration --- .../0025_add_change_request_project_permissions.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/api/projects/migrations/0025_add_change_request_project_permissions.py b/api/projects/migrations/0025_add_change_request_project_permissions.py index 92f05d493d58..2f68a79a6be2 100644 --- a/api/projects/migrations/0025_add_change_request_project_permissions.py +++ b/api/projects/migrations/0025_add_change_request_project_permissions.py @@ -11,9 +11,15 @@ def remove_default_project_permissions(apps, schema_model): - PermissionModel = apps.get_model("permissions", "PermissionModel") - PermissionModel.objects.get(key=MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS).delete() - PermissionModel.objects.get(key=APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS).delete() + PermissionModel = apps.get_model( # pragma: no cover + "permissions", "PermissionModel" + ) + PermissionModel.objects.get( # pragma: no cover + key=MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS + ).delete() + PermissionModel.objects.get( # pragma: no cover + key=APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS + ).delete() def insert_default_project_permissions(apps, schema_model): From 2127cd3ef27a8ec68988ac094d75c216c99b1afd Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 25 Sep 2024 14:59:40 +0000 Subject: [PATCH 083/122] Add pragma: no cover since this is a migration --- .../core/migrations/0011_add_project_to_change_requests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py b/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py index 023c7e5494b6..cae2e3f03403 100644 --- a/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py +++ b/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py @@ -10,8 +10,8 @@ def set_project_for_existing_environments(apps, schema_model): for change_request in ChangeRequest.objects.filter( environment_id__isnull=False ).select_related("environment"): - change_request.project = change_request.environment.project - change_request.save() + change_request.project = change_request.environment.project # pragma: no cover + change_request.save() # pragma: no cover class Migration(migrations.Migration): From fc7b5f876684bad88a8bd21e59dd0224e7e87176 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 25 Sep 2024 15:00:05 +0000 Subject: [PATCH 084/122] Add pragma: no cover since these exceptions are not possible due to the audit log failing first --- api/features/workflows/core/models.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index 198e9fc571e7..d8a3cb162de6 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -250,7 +250,7 @@ def is_approved(self): return self.is_approved_via_environment() if self.project: return self.is_approved_via_project() - raise RuntimeError( + raise RuntimeError( # pragma: no cover "Unable to approve change request without environment or project" ) @@ -283,7 +283,9 @@ def url(self): elif self.project_id: url += f"/projects/{self.project_id}" else: - raise RuntimeError("Change request missing fields for URL") + raise RuntimeError( # pragma: no cover + "Change request missing fields for URL" + ) url += f"/change-requests/{self.id}" return url From 5f983f23ce1ec58a9d6aa1f5da1e54e2639145a3 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 25 Sep 2024 15:00:43 +0000 Subject: [PATCH 085/122] Create a project change request fixture --- api/conftest.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/api/conftest.py b/api/conftest.py index a07c2036c5a0..d4c3dbfd2e36 100644 --- a/api/conftest.py +++ b/api/conftest.py @@ -519,6 +519,13 @@ def change_request(environment, admin_user): ) +@pytest.fixture() +def project_change_request(project: Project, admin_user: FFAdminUser) -> ChangeRequest: + return ChangeRequest.objects.create( + project=project, title="Test Project CR", user_id=admin_user.id + ) + + @pytest.fixture() def feature_state(feature: Feature, environment: Environment) -> FeatureState: return FeatureState.objects.get(environment=environment, feature=feature) From d35adc5fe40cdba9ad53fcee51e91b4cc350d0e1 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 25 Sep 2024 15:01:11 +0000 Subject: [PATCH 086/122] Add pragma: no cover since these are tested from the workflows repo's integration tests --- api/app/urls.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/api/app/urls.py b/api/app/urls.py index 43f55a3137ad..a736e5105996 100644 --- a/api/app/urls.py +++ b/api/app/urls.py @@ -55,13 +55,15 @@ if settings.WORKFLOWS_LOGIC_INSTALLED: workflow_views = importlib.import_module("workflows_logic.views") - from projects.views import ProjectViewSet + from projects.views import ProjectViewSet # pragma: no cover - router = routers.DefaultRouter() - router.register(r"projects", ProjectViewSet, basename="project") + router = routers.DefaultRouter() # pragma: no cover + router.register(r"projects", ProjectViewSet, basename="project") # pragma: no cover - project_router = routers.NestedSimpleRouter(router, r"projects", lookup="project") - project_router.register( + project_router = routers.NestedSimpleRouter( # pragma: no cover + router, r"projects", lookup="project" + ) + project_router.register( # pragma: no cover r"change-requests", workflow_views.ProjectChangeRequestViewSet, basename="project-change-requests", From 5a840f90826f9d40d9e8de8def528f83707cf6cf Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 25 Sep 2024 15:17:52 +0000 Subject: [PATCH 087/122] Trigger build From 18796e3c6cae3e10f99cf744db5ad640d271b137 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 3 Oct 2024 14:17:27 +0000 Subject: [PATCH 088/122] Switch urls to projects module --- api/app/urls.py | 19 +------------------ api/projects/urls.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/api/app/urls.py b/api/app/urls.py index a736e5105996..e7338cd5988d 100644 --- a/api/app/urls.py +++ b/api/app/urls.py @@ -4,7 +4,6 @@ from django.contrib import admin from django.urls import include, path, re_path from django.views.generic.base import TemplateView -from rest_framework_nested import routers from users.views import password_reset_redirect @@ -53,26 +52,10 @@ if settings.SAML_INSTALLED: urlpatterns.append(path("api/v1/auth/saml/", include("saml.urls"))) -if settings.WORKFLOWS_LOGIC_INSTALLED: +if settings.WORKFLOWS_LOGIC_INSTALLED: # pragma: no cover workflow_views = importlib.import_module("workflows_logic.views") - from projects.views import ProjectViewSet # pragma: no cover - - router = routers.DefaultRouter() # pragma: no cover - router.register(r"projects", ProjectViewSet, basename="project") # pragma: no cover - - project_router = routers.NestedSimpleRouter( # pragma: no cover - router, r"projects", lookup="project" - ) - project_router.register( # pragma: no cover - r"change-requests", - workflow_views.ProjectChangeRequestViewSet, - basename="project-change-requests", - ) - urlpatterns.extend( [ - path("api/v1/", include(router.urls)), - path("api/v1/", include(project_router.urls)), path("api/v1/features/workflows/", include("workflows_logic.urls")), path( "api/v1/environments//create-change-request/", diff --git a/api/projects/urls.py b/api/projects/urls.py index 4a38160dce16..b0150651f82a 100644 --- a/api/projects/urls.py +++ b/api/projects/urls.py @@ -1,3 +1,6 @@ +import importlib + +from django.conf import settings from django.urls import include, path, re_path from rest_framework_nested import routers @@ -67,6 +70,16 @@ ProjectAuditLogViewSet, basename="project-audit", ) + +if settings.WORKFLOWS_LOGIC_INSTALLED: # pragma: no cover + workflow_views = importlib.import_module("workflows_logic.views") + projects_router.register( + r"change-requests", + workflow_views.ProjectChangeRequestViewSet, + basename="project-change-requests", + ) + + nested_features_router = routers.NestedSimpleRouter( projects_router, r"features", lookup="feature" ) From 6b6e0d4de53afc81dfb01fed7331189f551f42f3 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 3 Oct 2024 15:37:51 +0000 Subject: [PATCH 089/122] Revise change request to account for test coverage and naming --- .../migrations/0011_add_project_to_change_requests.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py b/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py index cae2e3f03403..050d462afeb7 100644 --- a/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py +++ b/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py @@ -4,14 +4,14 @@ from django.db import migrations, models -def set_project_for_existing_environments(apps, schema_model): +def set_project_for_existing_change_requests(apps, schema_model): ChangeRequest = apps.get_model("workflows_core", "ChangeRequest") for change_request in ChangeRequest.objects.filter( environment_id__isnull=False ).select_related("environment"): - change_request.project = change_request.environment.project # pragma: no cover - change_request.save() # pragma: no cover + change_request.project = change_request.environment.project + change_request.save() class Migration(migrations.Migration): @@ -56,7 +56,7 @@ class Migration(migrations.Migration): ), ), migrations.RunPython( - set_project_for_existing_environments, + set_project_for_existing_change_requests, reverse_code=migrations.RunPython.noop, ), ] From 3c305849d40dd15334c34257eeab0ad8b04980f4 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 3 Oct 2024 15:38:22 +0000 Subject: [PATCH 090/122] Add typing --- api/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/conftest.py b/api/conftest.py index d4c3dbfd2e36..465c649430ab 100644 --- a/api/conftest.py +++ b/api/conftest.py @@ -513,7 +513,7 @@ def feature(project: Project, environment: Environment) -> Feature: @pytest.fixture() -def change_request(environment, admin_user): +def change_request(environment: Environment, admin_user: FFAdminUser) -> ChangeRequest: return ChangeRequest.objects.create( environment=environment, title="Test CR", user_id=admin_user.id ) From 46647f92904df984aa6cee167e60eb0dbf578f55 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 3 Oct 2024 15:39:24 +0000 Subject: [PATCH 091/122] Add migration test for 0011_add_project_to_change_requests.py --- .../core/test_unit_workflows_migrations.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 api/tests/unit/features/workflows/core/test_unit_workflows_migrations.py diff --git a/api/tests/unit/features/workflows/core/test_unit_workflows_migrations.py b/api/tests/unit/features/workflows/core/test_unit_workflows_migrations.py new file mode 100644 index 000000000000..38736946e5a8 --- /dev/null +++ b/api/tests/unit/features/workflows/core/test_unit_workflows_migrations.py @@ -0,0 +1,40 @@ +import pytest +from django.conf import settings +from django_test_migrations.migrator import Migrator + + +@pytest.mark.skipif( + settings.SKIP_MIGRATION_TESTS is True, + reason="Skip migration tests to speed up tests where necessary", +) +def test_migrate_add_project_to_change_request(migrator: Migrator) -> None: + old_state = migrator.apply_initial_migration( + ("workflows_core", "0010_add_ignore_conflicts_option"), + ) + OldOrganisation = old_state.apps.get_model("organisations", "Organisation") + OldProject = old_state.apps.get_model("projects", "Project") + OldEnvironment = old_state.apps.get_model("environments", "Environment") + OldFFAdminUser = old_state.apps.get_model("users", "FFAdminUser") + OldChangeRequest = old_state.apps.get_model("workflows_core", "ChangeRequest") + + organisation = OldOrganisation.objects.create(name="Test Org") + project = OldProject.objects.create(name="Test Project", organisation=organisation) + environment = OldEnvironment.objects.create( + name="Test Environment", project=project + ) + user = OldFFAdminUser.objects.create(email="staff@example.co") + change_request = OldChangeRequest.objects.create( + environment=environment, title="Test CR", user_id=user.id + ) + + assert hasattr(change_request, "project") is False + + # When + new_state = migrator.apply_tested_migration( + ("workflows_core", "0011_add_project_to_change_requests") + ) + + # Then + NewChangeRequest = new_state.apps.get_model("workflows_core", "ChangeRequest") + new_change_request = NewChangeRequest.objects.get(id=change_request.id) + assert new_change_request.project_id == project.id From 11305b1d7b0aac063afb66f0438d6a5ff0a42242 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 3 Oct 2024 15:58:07 +0000 Subject: [PATCH 092/122] Set project to be non-null --- .../migrations/0011_add_project_to_change_requests.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py b/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py index 050d462afeb7..088d84e547f8 100644 --- a/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py +++ b/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py @@ -59,4 +59,14 @@ class Migration(migrations.Migration): set_project_for_existing_change_requests, reverse_code=migrations.RunPython.noop, ), + migrations.AlterField( + model_name="changerequest", + name="project", + field=models.ForeignKey( + null=False, + on_delete=django.db.models.deletion.CASCADE, + related_name="change_requests", + to="projects.project", + ), + ), ] From 95f49602ae3a9bbbbddebf6ba0fdcf251f3850f0 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 3 Oct 2024 15:58:33 +0000 Subject: [PATCH 093/122] Set project as non-null and use the environment to default to the project --- api/features/workflows/core/models.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index d8a3cb162de6..64c877e98bc8 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -18,6 +18,7 @@ AFTER_CREATE, AFTER_SAVE, AFTER_UPDATE, + BEFORE_CREATE, BEFORE_DELETE, LifecycleModel, LifecycleModelMixin, @@ -80,9 +81,9 @@ class ChangeRequest( # Change requests get deleted in a delegated task when a project is deleted. project = models.ForeignKey( "projects.Project", - on_delete=models.SET_NULL, + on_delete=models.CASCADE, related_name="change_requests", - null=True, + null=False, ) environment = models.ForeignKey( @@ -293,6 +294,10 @@ def url(self): def email_subject(self): return f"Flagsmith Change Request: {self.title} (#{self.id})" + @hook(BEFORE_CREATE, when="project", is_now=None) + def set_project_from_environment(self): + self.project_id = self.environment.project_id + @hook(AFTER_CREATE, when="committed_at", is_not=None) @hook(AFTER_SAVE, when="committed_at", was=None, is_not=None) def create_audit_log_for_related_feature_state(self): From 63d10d05a2c0991833b36c4cac7a3a6d4a0d5f71 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 3 Oct 2024 18:21:50 +0000 Subject: [PATCH 094/122] Delete task and related testing logic --- api/features/workflows/core/tasks.py | 8 -------- .../workflows/core/test_unit_workflows_tasks.py | 14 -------------- 2 files changed, 22 deletions(-) delete mode 100644 api/features/workflows/core/tasks.py delete mode 100644 api/tests/unit/features/workflows/core/test_unit_workflows_tasks.py diff --git a/api/features/workflows/core/tasks.py b/api/features/workflows/core/tasks.py deleted file mode 100644 index 26b3f1708da1..000000000000 --- a/api/features/workflows/core/tasks.py +++ /dev/null @@ -1,8 +0,0 @@ -from task_processor.decorators import register_task_handler - -from features.workflows.core.models import ChangeRequest - - -@register_task_handler() -def delete_change_request(change_request_id: int) -> None: - ChangeRequest.objects.get(pk=change_request_id).delete() diff --git a/api/tests/unit/features/workflows/core/test_unit_workflows_tasks.py b/api/tests/unit/features/workflows/core/test_unit_workflows_tasks.py deleted file mode 100644 index 9a98566f5db0..000000000000 --- a/api/tests/unit/features/workflows/core/test_unit_workflows_tasks.py +++ /dev/null @@ -1,14 +0,0 @@ -from features.workflows.core.models import ChangeRequest -from features.workflows.core.tasks import delete_change_request - - -def test_delete_change_request(change_request: ChangeRequest) -> None: - # Given - assert change_request.deleted_at is None - - # When - delete_change_request(change_request_id=change_request.id) - - # Then - change_request.refresh_from_db() - assert change_request.deleted_at is not None From 0d8ede48808b862a453fe4d641efe598fea970e4 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 3 Oct 2024 18:22:34 +0000 Subject: [PATCH 095/122] Remove now-unnecessary task --- api/projects/tasks.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/api/projects/tasks.py b/api/projects/tasks.py index 713be8ec67ad..bbf54fa5b333 100644 --- a/api/projects/tasks.py +++ b/api/projects/tasks.py @@ -42,15 +42,11 @@ def handle_cascade_delete(project_id: int) -> None: from environments.tasks import delete_environment from features.tasks import delete_feature - from features.workflows.core.tasks import delete_change_request from projects.models import Project from segments.tasks import delete_segment project = Project.objects.all_with_deleted().get(id=project_id) - for change_request_id in project.change_requests.values_list("id", flat=True): - delete_change_request.delay(kwargs={"change_request_id": change_request_id}) - for environment_id in project.environments.values_list("id", flat=True): delete_environment.delay(kwargs={"environment_id": environment_id}) From 4a806f0336e4419c2dbc8578a8b44cf70dd7e996 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 3 Oct 2024 18:23:26 +0000 Subject: [PATCH 096/122] Update project related logic now that it's non-nullable --- api/features/workflows/core/models.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index 64c877e98bc8..782298b99e59 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -243,17 +243,13 @@ def get_audit_log_author(self, history_instance) -> typing.Optional["FFAdminUser def _get_environment(self) -> typing.Optional["Environment"]: return self.environment - def _get_project(self) -> typing.Optional["Project"]: - return self.project or (self.environment and self.environment.project) + def _get_project(self) -> "Project": + return self.project def is_approved(self): if self.environment: return self.is_approved_via_environment() - if self.project: - return self.is_approved_via_project() - raise RuntimeError( # pragma: no cover - "Unable to approve change request without environment or project" - ) + return self.is_approved_via_project() def is_approved_via_project(self): return self.project.minimum_change_request_approvals is None or ( @@ -281,12 +277,8 @@ def url(self): if self.environment: url += f"/project/{self.environment.project_id}" url += f"/environment/{self.environment.api_key}" - elif self.project_id: - url += f"/projects/{self.project_id}" else: - raise RuntimeError( # pragma: no cover - "Change request missing fields for URL" - ) + url += f"/projects/{self.project_id}" url += f"/change-requests/{self.id}" return url From c0ec3cb803c7ba261659580915bba3e7cf656003 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 3 Oct 2024 18:52:36 +0000 Subject: [PATCH 097/122] Update migration to remove dynamically loaded descriptions --- ..._add_change_request_project_permissions.py | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/api/projects/migrations/0025_add_change_request_project_permissions.py b/api/projects/migrations/0025_add_change_request_project_permissions.py index 2f68a79a6be2..673be8cc4674 100644 --- a/api/projects/migrations/0025_add_change_request_project_permissions.py +++ b/api/projects/migrations/0025_add_change_request_project_permissions.py @@ -10,30 +10,17 @@ ) -def remove_default_project_permissions(apps, schema_model): - PermissionModel = apps.get_model( # pragma: no cover - "permissions", "PermissionModel" - ) - PermissionModel.objects.get( # pragma: no cover - key=MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS - ).delete() - PermissionModel.objects.get( # pragma: no cover - key=APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS - ).delete() +def remove_default_project_permissions(apps, schema_model): # pragma: no cover + PermissionModel = apps.get_model("permissions", "PermissionModel") + PermissionModel.objects.get(key=MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS).delete() + PermissionModel.objects.get(key=APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS).delete() def insert_default_project_permissions(apps, schema_model): PermissionModel = apps.get_model("permissions", "PermissionModel") - manage_description = approve_description = None - - for project_permission in PROJECT_PERMISSIONS: - if project_permission[0] == MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS: - manage_description = project_permission[1] - elif project_permission[0] == APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS: - approve_description = project_permission[1] - assert manage_description - assert approve_description + manage_description = "Ability to manage change requests associated with a project." + approve_description = "Ability to approve project level change requests." PermissionModel.objects.get_or_create( key=MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS, From 539086c23ea1f99002847bbe14a61f5dcf63d998 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 3 Oct 2024 18:53:20 +0000 Subject: [PATCH 098/122] Add in minimum change request for approvals to serializer --- api/projects/serializers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/api/projects/serializers.py b/api/projects/serializers.py index a331a2fa73e5..9609c3fd7efa 100644 --- a/api/projects/serializers.py +++ b/api/projects/serializers.py @@ -43,6 +43,7 @@ class Meta: "show_edge_identity_overrides_for_feature", "stale_flags_limit_days", "edge_v2_migration_status", + "minimum_change_request_approvals", ) def get_migration_status(self, obj: Project) -> str: From 27d6338feeca850d5f8a01ce7da2a0294cecebc3 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 3 Oct 2024 19:00:26 +0000 Subject: [PATCH 099/122] Switch to project_id --- .../unit/features/workflows/core/test_unit_workflows_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py index 1441c4ea3307..37edd3e7059a 100644 --- a/api/tests/unit/features/workflows/core/test_unit_workflows_models.py +++ b/api/tests/unit/features/workflows/core/test_unit_workflows_models.py @@ -999,7 +999,7 @@ def test_url_via_project(project_change_request: ChangeRequest) -> None: url = project_change_request.url # Then - project_id = project_change_request.project.id + project_id = project_change_request.project_id expected_url = get_current_site_url() expected_url += ( f"/projects/{project_id}/change-requests/{project_change_request.id}" From ab253809704e2b97c3afe365242759426bcb6845 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 3 Oct 2024 19:45:20 +0000 Subject: [PATCH 100/122] Remove change request from project test --- api/tests/unit/projects/test_unit_projects_tasks.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/api/tests/unit/projects/test_unit_projects_tasks.py b/api/tests/unit/projects/test_unit_projects_tasks.py index af1aa8f79912..cc29d43dbd97 100644 --- a/api/tests/unit/projects/test_unit_projects_tasks.py +++ b/api/tests/unit/projects/test_unit_projects_tasks.py @@ -11,7 +11,6 @@ ) from environments.models import Environment from features.models import Feature -from features.workflows.core.models import ChangeRequest from projects.models import EdgeV2MigrationStatus, Project from projects.tasks import ( handle_cascade_delete, @@ -142,7 +141,6 @@ def test_handle_cascade_delete( feature: Feature, segment: Segment, settings: SettingsWrapper, - project_change_request: ChangeRequest, ) -> None: # Given settings.TASK_RUN_METHOD = TaskRunMethod.SYNCHRONOUSLY @@ -154,4 +152,3 @@ def test_handle_cascade_delete( assert not Environment.objects.filter(id=environment.id).exists() assert not Feature.objects.filter(id=feature.id).exists() assert not Segment.objects.filter(id=segment.id).exists() - assert not ChangeRequest.objects.filter(id=project_change_request.id).exists() From 04a1c559463499964c910faeb2fc78093373e5f8 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Fri, 4 Oct 2024 15:47:18 +0000 Subject: [PATCH 101/122] Update pyproject for build step --- api/poetry.lock | 18 +++++++++++------- api/pyproject.toml | 4 ++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index 83d165798e50..07d0b71a9eba 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -1353,15 +1353,16 @@ files = [] develop = false [package.dependencies] -django = "*" +django = "<5.0.0" djangorestframework = "*" drf-writable-nested = "*" +flagsmith-flag-engine = "*" [package.source] type = "git" url = "https://github.com/Flagsmith/flagsmith-common" -reference = "v1.0.0" -resolved_reference = "f3809f6d592b2c6cfdfa88e0b345ce722ac47727" +reference = "feat/add_workflows_change_request_concerns" +resolved_reference = "06db869ab34cf3c00d1afcbefc80661ba685027c" [[package]] name = "flagsmith-flag-engine" @@ -4056,13 +4057,16 @@ files = [] develop = false [package.dependencies] -flagsmith-common = {git = "https://github.com/Flagsmith/flagsmith-common", tag = "v1.0.0"} +djangorestframework = "*" +djangorestframework-recursive = "*" +flagsmith-common = {git = "https://github.com/Flagsmith/flagsmith-common", branch = "feat/add_workflows_change_request_concerns"} +flagsmith-flag-engine = "*" [package.source] type = "git" url = "https://github.com/flagsmith/flagsmith-workflows" -reference = "v2.5.0" -resolved_reference = "9fd951a470de537389c8d08c186656464500f3ed" +reference = "feat/add_change_requests_to_segments" +resolved_reference = "7cac4330b37442019c666325321d0056f264751b" [[package]] name = "wrapt" @@ -4181,4 +4185,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.11, <3.13" -content-hash = "39e82dd19f6474cd680ee9b42b36c2a3018b8dd1704e03fbdebdabdbaf620a96" +content-hash = "4e349cd8c92842e7e8753bc9169ac4b32c92669ca38808e293ce7dc07e6c458d" diff --git a/api/pyproject.toml b/api/pyproject.toml index 57b24ea7a734..213f262deb82 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -170,7 +170,7 @@ hubspot-api-client = "^8.2.1" djangorestframework-dataclasses = "^1.3.1" pyotp = "^2.9.0" flagsmith-task-processor = { git = "https://github.com/Flagsmith/flagsmith-task-processor", tag = "v1.0.2" } -flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common", tag = "v1.0.0" } +flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common", branch = "feat/add_workflows_change_request_concerns" } tzdata = "^2024.1" djangorestframework-simplejwt = "^5.3.1" @@ -196,7 +196,7 @@ flagsmith-ldap = { git = "https://github.com/flagsmith/flagsmith-ldap", tag = "v optional = true [tool.poetry.group.workflows.dependencies] -workflows-logic = { git = "https://github.com/flagsmith/flagsmith-workflows", tag = "v2.5.0" } +workflows-logic = { git = "https://github.com/flagsmith/flagsmith-workflows", branch = "feat/add_change_requests_to_segments" } [tool.poetry.group.dev.dependencies] django-test-migrations = "~1.2.0" From 4be57573cd9eebaad96614ac40dadcc9601d93bd Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 7 Oct 2024 13:37:06 +0000 Subject: [PATCH 102/122] Update lock --- api/poetry.lock | 2366 ++++++++++++++++++++++------------------------- 1 file changed, 1111 insertions(+), 1255 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index 07d0b71a9eba..852bc3ea4ef3 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -2,13 +2,13 @@ [[package]] name = "annotated-types" -version = "0.6.0" +version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" files = [ - {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, - {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, + {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]] @@ -24,13 +24,13 @@ files = [ [[package]] name = "argcomplete" -version = "3.1.2" +version = "3.5.1" description = "Bash tab completion for argparse" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "argcomplete-3.1.2-py3-none-any.whl", hash = "sha256:d97c036d12a752d1079f190bc1521c545b941fda89ad85d15afa909b4d1b9a99"}, - {file = "argcomplete-3.1.2.tar.gz", hash = "sha256:d5d1e5efd41435260b8f85673b74ea2e883affcbec9f4230c582689e8e78251b"}, + {file = "argcomplete-3.5.1-py3-none-any.whl", hash = "sha256:1a1d148bdaa3e3b93454900163403df41448a248af01b6e849edc5ac08e6c363"}, + {file = "argcomplete-3.5.1.tar.gz", hash = "sha256:eb1ee355aa2557bd3d0145de7b06b2a45b0ce461e1e7813f5d066039ab4177b4"}, ] [package.extras] @@ -78,21 +78,22 @@ files = [ [[package]] name = "attrs" -version = "23.1.0" +version = "24.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] [package.extras] -cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] -tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "autopep8" @@ -110,39 +111,40 @@ pycodestyle = ">=2.10.0" [[package]] name = "azure-core" -version = "1.28.0" +version = "1.31.0" description = "Microsoft Azure Core Library for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "azure-core-1.28.0.zip", hash = "sha256:e9eefc66fc1fde56dab6f04d4e5d12c60754d5a9fa49bdcfd8534fc96ed936bd"}, - {file = "azure_core-1.28.0-py3-none-any.whl", hash = "sha256:dec36dfc8eb0b052a853f30c07437effec2f9e3e1fc8f703d9bdaa5cfc0043d9"}, + {file = "azure_core-1.31.0-py3-none-any.whl", hash = "sha256:22954de3777e0250029360ef31d80448ef1be13b80a459bff80ba7073379e2cd"}, + {file = "azure_core-1.31.0.tar.gz", hash = "sha256:656a0dd61e1869b1506b7c6a3b31d62f15984b1a573d6326f6aa2f3e4123284b"}, ] [package.dependencies] -requests = ">=2.18.4" +requests = ">=2.21.0" six = ">=1.11.0" -typing-extensions = ">=4.3.0" +typing-extensions = ">=4.6.0" [package.extras] aio = ["aiohttp (>=3.0)"] [[package]] name = "azure-identity" -version = "1.16.1" +version = "1.18.0" description = "Microsoft Azure Identity Library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "azure-identity-1.16.1.tar.gz", hash = "sha256:6d93f04468f240d59246d8afde3091494a5040d4f141cad0f49fc0c399d0d91e"}, - {file = "azure_identity-1.16.1-py3-none-any.whl", hash = "sha256:8fb07c25642cd4ac422559a8b50d3e77f73dcc2bbfaba419d06d6c9d7cff6726"}, + {file = "azure_identity-1.18.0-py3-none-any.whl", hash = "sha256:bccf6106245b49ff41d0c4cd7b72851c5a2ba3a32cef7589da246f5727f26f02"}, + {file = "azure_identity-1.18.0.tar.gz", hash = "sha256:f567579a65d8932fa913c76eddf3305101a15e5727a5e4aa5df649a0f553d4c3"}, ] [package.dependencies] -azure-core = ">=1.23.0" +azure-core = ">=1.31.0" cryptography = ">=2.5" -msal = ">=1.24.0" -msal-extensions = ">=0.3.0" +msal = ">=1.30.0" +msal-extensions = ">=1.2.0" +typing-extensions = ">=4.0.0" [[package]] name = "backoff" @@ -201,17 +203,17 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "boto3" -version = "1.28.78" +version = "1.28.85" description = "The AWS SDK for Python" optional = false python-versions = ">= 3.7" files = [ - {file = "boto3-1.28.78-py3-none-any.whl", hash = "sha256:ff8df4bb5aeb69acc64959a74b31042bfc52d64ca77dbe845a72c8062c48d179"}, - {file = "boto3-1.28.78.tar.gz", hash = "sha256:aa970b1571321846543a6e615848352fe7621f1cb96b4454e919421924af95f7"}, + {file = "boto3-1.28.85-py3-none-any.whl", hash = "sha256:1fb7e7ba32a6701990168eb7a08e1fb624ae48130784dfab25904ed47deabb31"}, + {file = "boto3-1.28.85.tar.gz", hash = "sha256:96b4cb2708933cef7dbe1177df37ef0593839942978784147aade0e49511eb2b"}, ] [package.dependencies] -botocore = ">=1.31.78,<1.32.0" +botocore = ">=1.31.85,<1.32.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.7.0,<0.8.0" @@ -220,13 +222,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.31.78" +version = "1.31.85" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">= 3.7" files = [ - {file = "botocore-1.31.78-py3-none-any.whl", hash = "sha256:a9ca8deeb3f47a10a25637859fee8d81cac2db37ace819d24471279e44879547"}, - {file = "botocore-1.31.78.tar.gz", hash = "sha256:320c70bc412157813c2cf60217a592b4b345f8e97e4bf3b1ce49b6be69ed8965"}, + {file = "botocore-1.31.85-py3-none-any.whl", hash = "sha256:b8f35d65f2b45af50c36fc25cc1844d6bd61d38d2148b2ef133b8f10e198555d"}, + {file = "botocore-1.31.85.tar.gz", hash = "sha256:ce58e688222df73ec5691f934be1a2122a52c9d11d3037b586b3fff16ed6d25f"}, ] [package.dependencies] @@ -235,101 +237,104 @@ python-dateutil = ">=2.1,<3.0.0" urllib3 = {version = ">=1.25.4,<2.1", markers = "python_version >= \"3.10\""} [package.extras] -crt = ["awscrt (==0.16.26)"] +crt = ["awscrt (==0.19.12)"] [[package]] name = "cachetools" -version = "5.3.1" +version = "5.5.0" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" files = [ - {file = "cachetools-5.3.1-py3-none-any.whl", hash = "sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590"}, - {file = "cachetools-5.3.1.tar.gz", hash = "sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b"}, + {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, + {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, ] [[package]] name = "certifi" -version = "2024.7.4" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] name = "cffi" -version = "1.15.1" +version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, - {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, - {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, - {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, - {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, - {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, - {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, - {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, - {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, - {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, - {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, - {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, - {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, - {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, - {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, - {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, - {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, - {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, - {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [package.dependencies] @@ -337,23 +342,23 @@ pycparser = "*" [[package]] name = "cfgv" -version = "3.3.1" +version = "3.4.0" description = "Validate configuration and produce human readable error messages." optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.8" files = [ - {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, - {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, ] [[package]] name = "chargebee" -version = "2.37.1" +version = "2.44.1" description = "Python wrapper for the ChargeBee Subscription Billing API" optional = false python-versions = "*" files = [ - {file = "chargebee-2.37.1.tar.gz", hash = "sha256:14e53268dc434fe1d065fd5067e69e99f045dbd84a762016fb9c9d7734b740ce"}, + {file = "chargebee-2.44.1.tar.gz", hash = "sha256:a816c8f6591bb188e8b5cfb1c371971256b758fa42ce10d94100bcb9d48da4ab"}, ] [package.dependencies] @@ -361,97 +366,112 @@ requests = "*" [[package]] name = "charset-normalizer" -version = "3.2.0" +version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, - {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] [[package]] name = "click" -version = "8.1.6" +version = "8.1.7" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.6-py3-none-any.whl", hash = "sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5"}, - {file = "click-8.1.6.tar.gz", hash = "sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd"}, + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, ] [package.dependencies] @@ -501,63 +521,83 @@ jinja2 = "*" [[package]] name = "coverage" -version = "7.4.4" +version = "7.6.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2"}, - {file = "coverage-7.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf"}, - {file = "coverage-7.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8"}, - {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562"}, - {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2"}, - {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7"}, - {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87"}, - {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c"}, - {file = "coverage-7.4.4-cp310-cp310-win32.whl", hash = "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d"}, - {file = "coverage-7.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f"}, - {file = "coverage-7.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf"}, - {file = "coverage-7.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083"}, - {file = "coverage-7.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63"}, - {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f"}, - {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227"}, - {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd"}, - {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384"}, - {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b"}, - {file = "coverage-7.4.4-cp311-cp311-win32.whl", hash = "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286"}, - {file = "coverage-7.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec"}, - {file = "coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76"}, - {file = "coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818"}, - {file = "coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978"}, - {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70"}, - {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51"}, - {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c"}, - {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48"}, - {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9"}, - {file = "coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0"}, - {file = "coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e"}, - {file = "coverage-7.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384"}, - {file = "coverage-7.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1"}, - {file = "coverage-7.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a"}, - {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409"}, - {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e"}, - {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd"}, - {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7"}, - {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c"}, - {file = "coverage-7.4.4-cp38-cp38-win32.whl", hash = "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e"}, - {file = "coverage-7.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8"}, - {file = "coverage-7.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d"}, - {file = "coverage-7.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357"}, - {file = "coverage-7.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e"}, - {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e"}, - {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"}, - {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec"}, - {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd"}, - {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade"}, - {file = "coverage-7.4.4-cp39-cp39-win32.whl", hash = "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57"}, - {file = "coverage-7.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c"}, - {file = "coverage-7.4.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677"}, - {file = "coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, + {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, + {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, + {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, + {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, + {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, + {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, + {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, + {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, + {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, + {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, + {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, ] [package.extras] @@ -614,13 +654,13 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "datamodel-code-generator" -version = "0.25.8" +version = "0.25.9" description = "Datamodel Code Generator" optional = false python-versions = "<4.0,>=3.7" files = [ - {file = "datamodel_code_generator-0.25.8-py3-none-any.whl", hash = "sha256:f9b216efad84d8dcb517273d2728875b6052b7e8dc4e5c13a597441cef236f6e"}, - {file = "datamodel_code_generator-0.25.8.tar.gz", hash = "sha256:b7838122b8133dae6e46f36a1cf25c0ccc66745da057988f490d00ab71121de7"}, + {file = "datamodel_code_generator-0.25.9-py3-none-any.whl", hash = "sha256:9e0324233123d6e39a35bc0004771956935889a974aacfd7a0651de11d2219a9"}, + {file = "datamodel_code_generator-0.25.9.tar.gz", hash = "sha256:65ca9807d8edbd88a7f7931c10f4bc1c08bd9bbc5bb0508418a2b6a16590eb65"}, ] [package.dependencies] @@ -687,13 +727,13 @@ packaging = "*" [[package]] name = "dill" -version = "0.3.8" +version = "0.3.9" description = "serialize all of Python" optional = false python-versions = ">=3.8" files = [ - {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, - {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, + {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, + {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, ] [package.extras] @@ -702,13 +742,13 @@ profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "distlib" -version = "0.3.7" +version = "0.3.8" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, - {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, + {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, + {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, ] [[package]] @@ -724,13 +764,13 @@ files = [ [[package]] name = "django" -version = "4.2.15" +version = "4.2.16" description = "A high-level Python web framework that encourages rapid development and clean, pragmatic design." optional = false python-versions = ">=3.8" files = [ - {file = "Django-4.2.15-py3-none-any.whl", hash = "sha256:61ee4a130efb8c451ef3467c67ca99fdce400fedd768634efc86a68c18d80d30"}, - {file = "Django-4.2.15.tar.gz", hash = "sha256:c77f926b81129493961e19c0e02188f8d07c112a1162df69bfab178ae447f94a"}, + {file = "Django-4.2.16-py3-none-any.whl", hash = "sha256:1ddc333a16fc139fd253035a1606bb24261951bbc3a6ca256717fa06cc41a898"}, + {file = "Django-4.2.16.tar.gz", hash = "sha256:6f1616c2786c408ce86ab7e10f792b8f15742f7b7b7460243929cb371e7f1dad"}, ] [package.dependencies] @@ -843,13 +883,13 @@ Django = ">=2.2" [[package]] name = "django-health-check" -version = "3.18.2" +version = "3.18.3" description = "Run checks on services like databases, queue servers, celery processes, etc." optional = false python-versions = ">=3.8" files = [ - {file = "django_health_check-3.18.2-py2.py3-none-any.whl", hash = "sha256:16f9c9186236cbc2858fa0d0ecc3566ba2ad2b72683e5678d0d58eb9e8bbba1a"}, - {file = "django_health_check-3.18.2.tar.gz", hash = "sha256:21235120f8d756fa75ba430d0b0dbb04620fbd7bfac92ed6a0b911915ba38918"}, + {file = "django_health_check-3.18.3-py2.py3-none-any.whl", hash = "sha256:f5f58762b80bdf7b12fad724761993d6e83540f97e2c95c42978f187e452fa07"}, + {file = "django_health_check-3.18.3.tar.gz", hash = "sha256:18b75daca4551c69a43f804f9e41e23f5f5fb9efd06cf6a313b3d5031bb87bd0"}, ] [package.dependencies] @@ -861,23 +901,26 @@ test = ["boto3", "celery", "django-storages", "pytest", "pytest-cov", "pytest-dj [[package]] name = "django-ipware" -version = "5.0.0" +version = "7.0.1" description = "A Django application to retrieve user's IP address" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "django-ipware-5.0.0.tar.gz", hash = "sha256:4fa5607ee85e12ee5e158bc7569ff1e134fb1579681aa1ff3f0ed04be21be153"}, - {file = "django_ipware-5.0.0-py2.py3-none-any.whl", hash = "sha256:80b52a3f571a371519cc552798f1015b934dd5dd7738bfad87e101e861bd21b8"}, + {file = "django-ipware-7.0.1.tar.gz", hash = "sha256:d9ec43d2bf7cdf216fed8d494a084deb5761a54860a53b2e74346a4f384cff47"}, + {file = "django_ipware-7.0.1-py2.py3-none-any.whl", hash = "sha256:db16bbee920f661ae7f678e4270460c85850f03c6761a4eaeb489bdc91f64709"}, ] +[package.dependencies] +python-ipware = ">=2.0.3" + [[package]] name = "django-lifecycle" -version = "1.0.0" +version = "1.0.2" description = "Declarative model lifecycle hooks." optional = false python-versions = "*" files = [ - {file = "django-lifecycle-1.0.0.tar.gz", hash = "sha256:136c48e65d439cc34a6cb9a10d6d17611a9a5223f8249ee9c190ca5c7a67e9c1"}, + {file = "django-lifecycle-1.0.2.tar.gz", hash = "sha256:c5cb6127d15f5fa59a083f22accae189527a94b16057c56537e762ac4f3044c3"}, ] [package.dependencies] @@ -912,13 +955,13 @@ files = [ [[package]] name = "django-python3-ldap" -version = "0.15.6" +version = "0.15.8" description = "Django LDAP user authentication backend for Python 3." optional = false python-versions = "*" files = [ - {file = "django-python3-ldap-0.15.6.tar.gz", hash = "sha256:780ac3a2d20de17857990dd0a1bdb8f899855a59725c23638fd07f349439f588"}, - {file = "django_python3_ldap-0.15.6-py3-none-any.whl", hash = "sha256:04f59c25d76265e8f112d0563928877c5b08fa3422c4afea34912f02473e7fcb"}, + {file = "django_python3_ldap-0.15.8-py3-none-any.whl", hash = "sha256:bfd91dcb446c2cca33da195ed14d29513b2aba06f1d8ac2ef83009fa5826b518"}, + {file = "django_python3_ldap-0.15.8.tar.gz", hash = "sha256:5ca7800d02a3f25b1fd270a71ecf63cde4384c73b1982908e5e7aad6e37ea5ec"}, ] [package.dependencies] @@ -946,13 +989,13 @@ hiredis = ["redis[hiredis] (>=3,!=4.0.0,!=4.0.1)"] [[package]] name = "django-ses" -version = "3.5.0" -description = "A Django email backend for Amazon's Simple Email Service" +version = "3.5.2" +description = "A Django email backend for Amazon's Simple Email Service (SES)" optional = false -python-versions = ">=3.7,<4.0" +python-versions = ">=3.8,<4.0" files = [ - {file = "django_ses-3.5.0-py3-none-any.whl", hash = "sha256:3522fe531155eb06bb015b3b36324c059194450633b33f9bd5bc9d1328822fe2"}, - {file = "django_ses-3.5.0.tar.gz", hash = "sha256:dc1644f50608fbf3a64f085a371c61d56d68eba3c5efa69651f13dc3ba05049d"}, + {file = "django_ses-3.5.2-py3-none-any.whl", hash = "sha256:90c68cc6ca3467893faa8499981c81ba8ff2bd3f3acb08c06423a4142d6a0fc6"}, + {file = "django_ses-3.5.2.tar.gz", hash = "sha256:b6d94689bc15de02a11e84f05a5bf4a7895688e570c6f07c21698094debc6ced"}, ] [package.dependencies] @@ -1126,13 +1169,13 @@ test = ["cryptography", "freezegun", "pytest", "pytest-cov", "pytest-django", "p [[package]] name = "djoser" -version = "2.2.2" +version = "2.2.3" description = "REST implementation of Django authentication system." optional = false -python-versions = ">=3.8,<4.0" +python-versions = "<4.0,>=3.8" files = [ - {file = "djoser-2.2.2-py3-none-any.whl", hash = "sha256:efb91ad61e4d5b8d664db029b5947df9d34078289ef2680a1ab665e047144b74"}, - {file = "djoser-2.2.2.tar.gz", hash = "sha256:9deb831a1c8781ceff325699e1407b4e1be8b4588e87071621d88ba31c09349f"}, + {file = "djoser-2.2.3-py3-none-any.whl", hash = "sha256:1325e5c1ee3233560e3737fc8fe2ab4b014c5adb98a01682f30ef250aaabafba"}, + {file = "djoser-2.2.3.tar.gz", hash = "sha256:28545bfb15096dd26e0d74b49b4dd267c0a8d5f9d562225ecc60c83289799131"}, ] [package.dependencies] @@ -1147,21 +1190,21 @@ webauthn = ["webauthn (<1.0)"] [[package]] name = "dnspython" -version = "2.6.1" +version = "2.7.0" description = "DNS toolkit" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"}, - {file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"}, + {file = "dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86"}, + {file = "dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1"}, ] [package.extras] -dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "sphinx (>=7.2.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] -dnssec = ["cryptography (>=41)"] +dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=7)", "hypercorn (>=0.16.0)", "mypy (>=1.8)", "pylint (>=3)", "pytest (>=7.4)", "pytest-cov (>=4.1.0)", "quart-trio (>=0.11.0)", "sphinx (>=7.2.0)", "sphinx-rtd-theme (>=2.0.0)", "twine (>=4.0.0)", "wheel (>=0.42.0)"] +dnssec = ["cryptography (>=43)"] doh = ["h2 (>=4.1.0)", "httpcore (>=1.0.0)", "httpx (>=0.26.0)"] -doq = ["aioquic (>=0.9.25)"] -idna = ["idna (>=3.6)"] +doq = ["aioquic (>=1.0.0)"] +idna = ["idna (>=3.7)"] trio = ["trio (>=0.23)"] wmi = ["wmi (>=1.5.1)"] @@ -1216,27 +1259,27 @@ validation = ["swagger-spec-validator (>=2.1.0)"] [[package]] name = "elementpath" -version = "4.1.5" +version = "4.5.0" description = "XPath 1.0/2.0/3.0/3.1 parsers and selectors for ElementTree and lxml" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "elementpath-4.1.5-py3-none-any.whl", hash = "sha256:2ac1a2fb31eb22bbbf817f8cf6752f844513216263f0e3892c8e79782fe4bb55"}, - {file = "elementpath-4.1.5.tar.gz", hash = "sha256:c2d6dc524b29ef751ecfc416b0627668119d8812441c555d7471da41d4bacb8d"}, + {file = "elementpath-4.5.0-py3-none-any.whl", hash = "sha256:a16438bcc6b2b3069dde204c1e105322378a108b28faea3055d1b294443babea"}, + {file = "elementpath-4.5.0.tar.gz", hash = "sha256:affdc8de95af1a4c10d1d2ed79c6fa56b59c26c7fce64b73497569e9dea46998"}, ] [package.extras] -dev = ["Sphinx", "coverage", "flake8", "lxml", "lxml-stubs", "memory-profiler", "memray", "mypy", "tox", "xmlschema (>=2.0.0)"] +dev = ["Sphinx", "coverage", "flake8", "lxml", "lxml-stubs", "memory-profiler", "memray", "mypy", "tox", "xmlschema (>=3.3.2)"] [[package]] name = "email-validator" -version = "2.0.0.post2" +version = "2.2.0" description = "A robust email address syntax and deliverability validation library." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "email_validator-2.0.0.post2-py3-none-any.whl", hash = "sha256:2466ba57cda361fb7309fd3d5a225723c788ca4bbad32a0ebd5373b99730285c"}, - {file = "email_validator-2.0.0.post2.tar.gz", hash = "sha256:1ff6e86044200c56ae23595695c54e9614f4a9551e0e393614f764860b3d7900"}, + {file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"}, + {file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"}, ] [package.dependencies] @@ -1295,34 +1338,35 @@ pyrepl = ">=0.8.2" [[package]] name = "filelock" -version = "3.12.2" +version = "3.16.1" description = "A platform independent file lock." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, - {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, ] [package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] +typing = ["typing-extensions (>=4.12.2)"] [[package]] name = "flagsmith" -version = "3.6.0" +version = "3.8.0" description = "Flagsmith Python SDK" optional = false -python-versions = ">=3.8.1,<4" +python-versions = "<4,>=3.8.1" files = [ - {file = "flagsmith-3.6.0.tar.gz", hash = "sha256:b189bea8def2a01f2fc2c53a71dcf917ed088a68d8478f7aed4575c488782632"}, + {file = "flagsmith-3.8.0.tar.gz", hash = "sha256:0ed401d32978632e9ea156418f7e479bdae8bd879354164d667721ece972d878"}, ] [package.dependencies] flagsmith-flag-engine = ">=5.1.0,<6.0.0" -pytz = ">=2023.4,<2024.0" -requests = ">=2.27.1,<3.0.0" -requests-futures = ">=1.0.0,<2.0.0" +pydantic = ">=2,<3" +requests = ">=2.32.3,<3.0.0" +requests-futures = ">=1.0.1,<2.0.0" sseclient-py = ">=1.8.0,<2.0.0" [[package]] @@ -1362,16 +1406,16 @@ flagsmith-flag-engine = "*" type = "git" url = "https://github.com/Flagsmith/flagsmith-common" reference = "feat/add_workflows_change_request_concerns" -resolved_reference = "06db869ab34cf3c00d1afcbefc80661ba685027c" +resolved_reference = "963c8a3dd5efc091fe7686134c760e396e87b2db" [[package]] name = "flagsmith-flag-engine" -version = "5.2.0" +version = "5.3.0" description = "Flag engine for the Flagsmith API." optional = false python-versions = "*" files = [ - {file = "flagsmith-flag-engine-5.2.0.tar.gz", hash = "sha256:247da79a9fee55a55de1440fcd112de9b56cef9d5feb8c783319a9e0620e3a72"}, + {file = "flagsmith-flag-engine-5.3.0.tar.gz", hash = "sha256:87007f6a312cf11b2c201acd54b30f17de8aa039c3c56af431f1ed3c743fa84c"}, ] [package.dependencies] @@ -1423,13 +1467,13 @@ resolved_reference = "1424d95cbadd18dfc57debbdf0ea2d3d13ea1446" [[package]] name = "freezegun" -version = "1.2.2" +version = "1.5.1" description = "Let your Python tests travel through time" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "freezegun-1.2.2-py3-none-any.whl", hash = "sha256:ea1b963b993cb9ea195adbd893a48d573fda951b0da64f60883d7e988b606c9f"}, - {file = "freezegun-1.2.2.tar.gz", hash = "sha256:cd22d1ba06941384410cd967d8a99d5ae2442f57dfafeff2fda5de8dc5c05446"}, + {file = "freezegun-1.5.1-py3-none-any.whl", hash = "sha256:bf111d7138a8abe55ab48a71755673dbaa4ab87f4cff5634a4442dfec34c15f1"}, + {file = "freezegun-1.5.1.tar.gz", hash = "sha256:b29dedfcda6d5e8e083ce71b2b542753ad48cfec44037b3fc79702e2980a89e9"}, ] [package.dependencies] @@ -1437,29 +1481,31 @@ python-dateutil = ">=2.7" [[package]] name = "genson" -version = "1.2.2" +version = "1.3.0" description = "GenSON is a powerful, user-friendly JSON Schema generator." optional = false python-versions = "*" files = [ - {file = "genson-1.2.2.tar.gz", hash = "sha256:8caf69aa10af7aee0e1a1351d1d06801f4696e005f06cedef438635384346a16"}, + {file = "genson-1.3.0-py3-none-any.whl", hash = "sha256:468feccd00274cc7e4c09e84b08704270ba8d95232aa280f65b986139cec67f7"}, + {file = "genson-1.3.0.tar.gz", hash = "sha256:e02db9ac2e3fd29e65b5286f7135762e2cd8a986537c075b06fc5f1517308e37"}, ] [[package]] name = "google-api-core" -version = "2.11.1" +version = "2.20.0" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.11.1.tar.gz", hash = "sha256:25d29e05a0058ed5f19c61c0a78b1b53adea4d9364b464d014fbda941f6d1c9a"}, - {file = "google_api_core-2.11.1-py3-none-any.whl", hash = "sha256:d92a5a92dc36dd4f4b9ee4e55528a90e432b059f93aee6ad857f9de8cc7ae94a"}, + {file = "google_api_core-2.20.0-py3-none-any.whl", hash = "sha256:ef0591ef03c30bb83f79b3d0575c3f31219001fc9c5cf37024d08310aeffed8a"}, + {file = "google_api_core-2.20.0.tar.gz", hash = "sha256:f74dff1889ba291a4b76c5079df0711810e2d9da81abfdc99957bc961c1eb28f"}, ] [package.dependencies] google-auth = ">=2.14.1,<3.0.dev0" googleapis-common-protos = ">=1.56.2,<2.0.dev0" -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,<5.0.0.dev0" +proto-plus = ">=1.22.3,<2.0.0dev" +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,<6.0.0.dev0" requests = ">=2.18.0,<3.0.0.dev0" [package.extras] @@ -1488,374 +1534,115 @@ uritemplate = ">=3.0.0,<4dev" [[package]] name = "google-auth" -version = "2.22.0" +version = "2.35.0" description = "Google Authentication Library" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "google-auth-2.22.0.tar.gz", hash = "sha256:164cba9af4e6e4e40c3a4f90a1a6c12ee56f14c0b4868d1ca91b32826ab334ce"}, - {file = "google_auth-2.22.0-py2.py3-none-any.whl", hash = "sha256:d61d1b40897407b574da67da1a833bdc10d5a11642566e506565d1b1a46ba873"}, + {file = "google_auth-2.35.0-py2.py3-none-any.whl", hash = "sha256:25df55f327ef021de8be50bad0dfd4a916ad0de96da86cd05661c9297723ad3f"}, + {file = "google_auth-2.35.0.tar.gz", hash = "sha256:f4c64ed4e01e8e8b646ef34c018f8bf3338df0c8e37d8b3bba40e7f574a3278a"}, ] [package.dependencies] cachetools = ">=2.0.0,<6.0" pyasn1-modules = ">=0.2.1" rsa = ">=3.1.4,<5" -six = ">=1.9.0" -urllib3 = "<2.0" [package.extras] aiohttp = ["aiohttp (>=3.6.2,<4.0.0.dev0)", "requests (>=2.20.0,<3.0.0.dev0)"] -enterprise-cert = ["cryptography (==36.0.2)", "pyopenssl (==22.0.0)"] +enterprise-cert = ["cryptography", "pyopenssl"] pyopenssl = ["cryptography (>=38.0.3)", "pyopenssl (>=20.0.0)"] reauth = ["pyu2f (>=0.1.5)"] requests = ["requests (>=2.20.0,<3.0.0.dev0)"] [[package]] name = "google-auth-httplib2" -version = "0.1.0" +version = "0.2.0" description = "Google Authentication Library: httplib2 transport" optional = false python-versions = "*" files = [ - {file = "google-auth-httplib2-0.1.0.tar.gz", hash = "sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac"}, - {file = "google_auth_httplib2-0.1.0-py2.py3-none-any.whl", hash = "sha256:31e49c36c6b5643b57e82617cb3e021e3e1d2df9da63af67252c02fa9c1f4a10"}, + {file = "google-auth-httplib2-0.2.0.tar.gz", hash = "sha256:38aa7badf48f974f1eb9861794e9c0cb2a0511a4ec0679b1f886d108f5640e05"}, + {file = "google_auth_httplib2-0.2.0-py2.py3-none-any.whl", hash = "sha256:b65a0a2123300dd71281a7bf6e64d65a0759287df52729bdd1ae2e47dc311a3d"}, ] [package.dependencies] google-auth = "*" -httplib2 = ">=0.15.0" -six = "*" +httplib2 = ">=0.19.0" [[package]] name = "google-re2" -version = "1.1" +version = "1.1.20240702" description = "RE2 Python bindings" optional = false python-versions = "~=3.8" files = [ - {file = "google-re2-1.1.tar.gz", hash = "sha256:d3a9467ee52b46ac77ca928f6d0cbeaccfd92f03ca0f0f65b9df6a95184f3a1c"}, - {file = "google_re2-1.1-1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:874d2e36dfa506b03d4f9c4aef1701a65304f4004c96c7edac7d8aea08fe193e"}, - {file = "google_re2-1.1-1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b66eb84850afdce09aabca40bcd6f2a0e96178a1b4990d555678edb1f59bf255"}, - {file = "google_re2-1.1-1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:c461640a07db26dc2b51f43de607b7520e7debaf4f6a000f796a3c0196ca52af"}, - {file = "google_re2-1.1-1-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:7f9ba69eaee6e7a9f5ddfb919bf1a866af14a18b26a179e3fb1a6fe3d0cbf349"}, - {file = "google_re2-1.1-1-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:f95cf16739cc3ea63728366881221b119f2322b4b739b7da6522d45a68792cea"}, - {file = "google_re2-1.1-1-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:9fb56a41250191298e6a2859b0fdea1e83330c9870fe8d84e5836c506ae46e96"}, - {file = "google_re2-1.1-1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fb22ea995564d87baf4a4bfbb3ca024be913683a710f4f0dc9c94dc663afab20"}, - {file = "google_re2-1.1-1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:19b3f0bfbb2a2ca58ed0aaa9356d07a5c0921383a6dbeca086b2b74472f5ee08"}, - {file = "google_re2-1.1-1-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:34fd7f97b84af7453cf05b25adfe2491ba3cef1ca548ac2907efa63d3510954d"}, - {file = "google_re2-1.1-1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3e029664192d8d30f7c977706183ef483e82ca239302272df74e01d2e22897ca"}, - {file = "google_re2-1.1-1-cp310-cp310-win32.whl", hash = "sha256:41a8f222f9839d059d37efd28e4deec203502d7e39c3759d83d6a33deadf1d2e"}, - {file = "google_re2-1.1-1-cp310-cp310-win_amd64.whl", hash = "sha256:6141d569fdf72aa693f040ba05c469036587395af07ff419b9a3c009d6ffefd3"}, - {file = "google_re2-1.1-1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2d03f6aaf22788ba13a770f0d183b8eebe55545bcbb6e4c41dcccac7ded014d"}, - {file = "google_re2-1.1-1-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:a98f15fd9c31bf80d368698447191a2e9703880b305dbf34d9a63ce634b8a557"}, - {file = "google_re2-1.1-1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:42128916cc2966623832aabbd224c88e862d1c531d6bc49ab141f565e6321a90"}, - {file = "google_re2-1.1-1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:6e27986a166903ad7000635f6faed8ab5072d687f822ac9f692c40b2470aebcf"}, - {file = "google_re2-1.1-1-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:5e9edcd743a830d0c0b2729201e42ab86fceef8f4086df65563f482e4544359e"}, - {file = "google_re2-1.1-1-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:d33145bbfd32e916f1c911cd9225be5364a36c3959742a0cc4dfc0692d6a2a5e"}, - {file = "google_re2-1.1-1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8b27cc2544b69a357ab2a749dc0c13a1b9055198c56f4c2c3b0f61d693f8e203"}, - {file = "google_re2-1.1-1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3cdf8982b6def987e95b37984d0c1c878de32635dd78acde3273f730b69708c9"}, - {file = "google_re2-1.1-1-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:71ac661a7365e134741fe5542f13d7ce1e6187446b96ddee4c8b7d153fc8f05a"}, - {file = "google_re2-1.1-1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:35a902ba31a71a3e9e114e44473624d9aa9f9b85ec981bfa91671aefe0ef1a6c"}, - {file = "google_re2-1.1-1-cp311-cp311-win32.whl", hash = "sha256:9469f26b485da2784c658e687a766c72e1a17b1e63b3ed24b5f64c3d19fbae3d"}, - {file = "google_re2-1.1-1-cp311-cp311-win_amd64.whl", hash = "sha256:07dd0780240ee431781119b46c3bbf76f5cef24a2cbb542f6a08c643e0a68d98"}, - {file = "google_re2-1.1-1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9857dc4d69b8025057c8129e98406a24d51bdaf1b96e481dbba7e69e0ec85104"}, - {file = "google_re2-1.1-1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:a6eaaa5f200022eb0bdded5949c91454fc96e1edd6f9e9a96dd1dc32c821c00e"}, - {file = "google_re2-1.1-1-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a32bb2afe128d90b8edc20d4f7d297f7e2753206eba92937a57e5280736eac74"}, - {file = "google_re2-1.1-1-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:4f2754616c61b76ab4e5a4f39892a52a00897203b859c5abd7e3c630dd883cda"}, - {file = "google_re2-1.1-1-cp38-cp38-macosx_13_0_arm64.whl", hash = "sha256:b110f3d657e8f67a43a699d327ce47095b80180ea1118e2de44cb5c7002503d9"}, - {file = "google_re2-1.1-1-cp38-cp38-macosx_13_0_x86_64.whl", hash = "sha256:fd62ba2853eef65e249a9c4437a9ecac568222062bc956f0c61a3d1151a6271b"}, - {file = "google_re2-1.1-1-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23b50eb74dc3e1d480b04b987c61242df5dade50d08bc16e25eb3582b83fca80"}, - {file = "google_re2-1.1-1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e1bde89855dd5ab0811187d21eec149975510c80e865c771c883524a452445e7"}, - {file = "google_re2-1.1-1-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10c6cddc720151a509beb98ab310fa0cc8bcb265f83518ebf831de2c9ff73af0"}, - {file = "google_re2-1.1-1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bea09c5e8401ec50b8f211bc820ec2f0ca5e744ac67431a1b39bdacbd266553"}, - {file = "google_re2-1.1-1-cp38-cp38-win32.whl", hash = "sha256:ffa51b118037518bcdf63c7649d0b4be7071982b83f48ee3bbabf24a9cb48f8a"}, - {file = "google_re2-1.1-1-cp38-cp38-win_amd64.whl", hash = "sha256:3b47715b6d43c9351957eb5092ad0fa625d04106d81f34cb8a726c53395ad474"}, - {file = "google_re2-1.1-1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:998f31bf7efbc9bb603d0c356c1c77e5331f689c71783df8e21e67bb025fc66a"}, - {file = "google_re2-1.1-1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:0b5f0eaab859d3ba5f462c82bf37ab56e9d37e19b40b5898c731dbe4213a85f7"}, - {file = "google_re2-1.1-1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:f6d591d9c4cbc7142b729ddcc3f654d059d8ebc3bc95891198808a4785a6b4d8"}, - {file = "google_re2-1.1-1-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:3c325c2eae197b423330a04ab62e2e1cf942676cd5560907db4d63e23ce0648a"}, - {file = "google_re2-1.1-1-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:1e019e8f57955806ee843254ce454249b58800a6e872b2c8e9df2ef3459de0d5"}, - {file = "google_re2-1.1-1-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:58ebbcc7ad2b639768a6bca586357291660ea40dfac83039208e5055c357513b"}, - {file = "google_re2-1.1-1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:723f8553e7fc022294071f14fb7dfc7958c365dc7d4a71d4938ccd2df8c6eca4"}, - {file = "google_re2-1.1-1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d81512b08e6787fc8ef29fea365d3fdbf957553a625550e1d96c36877ae30355"}, - {file = "google_re2-1.1-1-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c58601b155651cc572a23ee2860788c77581aad85d3567a55b89b0674702f34d"}, - {file = "google_re2-1.1-1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c6c9f64b9724ec38da8e514f404ac64e9a6a5e8b1d7031c2dadd05c1f4c16fd"}, - {file = "google_re2-1.1-1-cp39-cp39-win32.whl", hash = "sha256:d1b751b9ab9f8e2ab2a36d72b909281ce65f328c9115a1685acae1a2d1afd7a4"}, - {file = "google_re2-1.1-1-cp39-cp39-win_amd64.whl", hash = "sha256:ac775c75cec7069351d201da4e0fb0cae4c1c5ebecd08fa34e1be89740c1d80b"}, - {file = "google_re2-1.1-2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5eaefe4705b75ca5f78178a50104b689e9282f868e12f119b26b4cffc0c7ee6e"}, - {file = "google_re2-1.1-2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:e35f2c8aabfaaa4ce6420b3cae86c0c29042b1b4f9937254347e9b985694a171"}, - {file = "google_re2-1.1-2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:35fd189cbaaaa39c9a6a8a00164c8d9c709bacd0c231c694936879609beff516"}, - {file = "google_re2-1.1-2-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:60475d222cebd066c80414831c8a42aa2449aab252084102ee05440896586e6a"}, - {file = "google_re2-1.1-2-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:871cb85b9b0e1784c983b5c148156b3c5314cb29ca70432dff0d163c5c08d7e5"}, - {file = "google_re2-1.1-2-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:94f4e66e34bdb8de91ec6cdf20ba4fa9fea1dfdcfb77ff1f59700d01a0243664"}, - {file = "google_re2-1.1-2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1563577e2b720d267c4cffacc0f6a2b5c8480ea966ebdb1844fbea6602c7496f"}, - {file = "google_re2-1.1-2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:49b7964532a801b96062d78c0222d155873968f823a546a3dbe63d73f25bb56f"}, - {file = "google_re2-1.1-2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2362fd70eb639a75fd0187d28b4ba7b20b3088833d8ad7ffd8693d0ba159e1c2"}, - {file = "google_re2-1.1-2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86b80719636a4e21391e20a9adf18173ee6ae2ec956726fe2ff587417b5e8ba6"}, - {file = "google_re2-1.1-2-cp310-cp310-win32.whl", hash = "sha256:5456fba09df951fe8d1714474ed1ecda102a68ddffab0113e6c117d2e64e6f2b"}, - {file = "google_re2-1.1-2-cp310-cp310-win_amd64.whl", hash = "sha256:2ac6936a3a60d8d9de9563e90227b3aea27068f597274ca192c999a12d8baa8f"}, - {file = "google_re2-1.1-2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5a87b436028ec9b0f02fe19d4cbc19ef30441085cdfcdf1cce8fbe5c4bd5e9a"}, - {file = "google_re2-1.1-2-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:fc0d4163de9ed2155a77e7a2d59d94c348a6bbab3cff88922fab9e0d3d24faec"}, - {file = "google_re2-1.1-2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:48b12d953bc796736e7831d67b36892fb6419a4cc44cb16521fe291e594bfe23"}, - {file = "google_re2-1.1-2-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:62c780c927cff98c1538439f0ff616f48a9b2e8837c676f53170d8ae5b9e83cb"}, - {file = "google_re2-1.1-2-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:04b2aefd768aa4edeef8b273327806c9cb0b82e90ff52eacf5d11003ac7a0db2"}, - {file = "google_re2-1.1-2-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:9c90175992346519ee7546d9af9a64541c05b6b70346b0ddc54a48aa0d3b6554"}, - {file = "google_re2-1.1-2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22ad9ad9d125249d6386a2e80efb9de7af8260b703b6be7fa0ab069c1cf56ced"}, - {file = "google_re2-1.1-2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f70971f6ffe5254e476e71d449089917f50ebf9cf60f9cec80975ab1693777e2"}, - {file = "google_re2-1.1-2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f267499529e64a4abed24c588f355ebe4700189d434d84a7367725f5a186e48d"}, - {file = "google_re2-1.1-2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b632eff5e4cd44545a9c0e52f2e1becd55831e25f4dd4e0d7ec8ee6ca50858c1"}, - {file = "google_re2-1.1-2-cp311-cp311-win32.whl", hash = "sha256:a42c733036e8f242ee4e5f0e27153ad4ca44ced9e4ce82f3972938ddee528db0"}, - {file = "google_re2-1.1-2-cp311-cp311-win_amd64.whl", hash = "sha256:64f8eed4ca96905d99b5286b3d14b5ca4f6a025ff3c1351626a7df2f93ad1ddd"}, - {file = "google_re2-1.1-2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5541efcca5b5faf7e0d882334a04fa479bad4e7433f94870f46272eec0672c4a"}, - {file = "google_re2-1.1-2-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:92309af35b6eb2d3b3dc57045cdd83a76370958ab3e0edd2cc4638f6d23f5b32"}, - {file = "google_re2-1.1-2-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:197cd9bcaba96d18c5bf84d0c32fca7a26c234ea83b1d3083366f4392cb99f78"}, - {file = "google_re2-1.1-2-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:1b896f171d29b541256cf26e10dccc9103ac1894683914ed88828ca6facf8dca"}, - {file = "google_re2-1.1-2-cp38-cp38-macosx_13_0_arm64.whl", hash = "sha256:e022d3239b945014e916ca7120fee659b246ec26c301f9e0542f1a19b38a8744"}, - {file = "google_re2-1.1-2-cp38-cp38-macosx_13_0_x86_64.whl", hash = "sha256:2c73f8a9440873b68bee1198094377501065e85aaf6fcc0d2512c7589ffa06ca"}, - {file = "google_re2-1.1-2-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:901d86555bd7725506d651afaba7d71cd4abd13260aed6cfd7c641a45f76d4f6"}, - {file = "google_re2-1.1-2-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ce4710ff636701cfb56eb91c19b775d53b03749a23b7d2a5071bbbf4342a9067"}, - {file = "google_re2-1.1-2-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:76a20e5ebdf5bc5d430530197e42a2eeb562f729d3a3fb51f39168283d676e66"}, - {file = "google_re2-1.1-2-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:77c9f4d4bb1c8de9d2642d3c4b8b615858ba764df025b3b4f1310266f8def269"}, - {file = "google_re2-1.1-2-cp38-cp38-win32.whl", hash = "sha256:94bd60785bf37ef130a1613738e3c39465a67eae3f3be44bb918540d39b68da3"}, - {file = "google_re2-1.1-2-cp38-cp38-win_amd64.whl", hash = "sha256:59efeb77c0dcdbe37794c61f29c5b1f34bc06e8ec309a111ccdd29d380644d70"}, - {file = "google_re2-1.1-2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:221e38c27e1dd9ccb8e911e9c7aed6439f68ce81e7bb74001076830b0d6e931d"}, - {file = "google_re2-1.1-2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:d9145879e6c2e1b814445300b31f88a675e1f06c57564670d95a1442e8370c27"}, - {file = "google_re2-1.1-2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:c8a12f0740e2a52826bdbf95569a4b0abdf413b4012fa71e94ad25dd4715c6e5"}, - {file = "google_re2-1.1-2-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:9c9998f71466f4db7bda752aa7c348b2881ff688e361108fe500caad1d8b9cb2"}, - {file = "google_re2-1.1-2-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:0c39f69b702005963a3d3bf78743e1733ad73efd7e6e8465d76e3009e4694ceb"}, - {file = "google_re2-1.1-2-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:6d0ce762dee8d6617d0b1788a9653e805e83a23046c441d0ea65f1e27bf84114"}, - {file = "google_re2-1.1-2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ecf3619d98c9b4a7844ab52552ad32597cdbc9a5bdbc7e3435391c653600d1e2"}, - {file = "google_re2-1.1-2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9a1426a8cbd1fa004974574708d496005bd379310c4b1c7012be4bc75efde7a8"}, - {file = "google_re2-1.1-2-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1a30626ba48b4070f3eab272d860ef1952e710b088792c4d68dddb155be6bfc"}, - {file = "google_re2-1.1-2-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1b9c1ffcfbc3095b6ff601ec2d2bf662988f6ea6763bc1c9d52bec55881f8fde"}, - {file = "google_re2-1.1-2-cp39-cp39-win32.whl", hash = "sha256:32ecf995a252c0548404c1065ba4b36f1e524f1f4a86b6367a1a6c3da3801e30"}, - {file = "google_re2-1.1-2-cp39-cp39-win_amd64.whl", hash = "sha256:e7865410f3b112a3609739283ec3f4f6f25aae827ff59c6bfdf806fd394d753e"}, - {file = "google_re2-1.1-3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3b21f83f0a201009c56f06fcc7294a33555ede97130e8a91b3f4cae01aed1d73"}, - {file = "google_re2-1.1-3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b38194b91354a38db1f86f25d09cdc6ac85d63aee4c67b43da3048ce637adf45"}, - {file = "google_re2-1.1-3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:e7da3da8d6b5a18d6c3b61b11cc5b66b8564eaedce99d2312b15b6487730fc76"}, - {file = "google_re2-1.1-3-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:aeca656fb10d8638f245331aabab59c9e7e051ca974b366dd79e6a9efb12e401"}, - {file = "google_re2-1.1-3-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:2069d6dc94f5fa14a159bf99cad2f11e9c0f8ec3b7f44a4dde9e59afe5d1c786"}, - {file = "google_re2-1.1-3-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:2319a39305a4931cb5251451f2582713418a19bef2af7adf9e2a7a0edd939b99"}, - {file = "google_re2-1.1-3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb98fc131699756c6d86246f670a5e1c1cc1ba85413c425ad344cb30479b246c"}, - {file = "google_re2-1.1-3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a6e038986d8ffe4e269f8532f03009f229d1f6018d4ac0dabc8aff876338f6e0"}, - {file = "google_re2-1.1-3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8618343ee658310e0f53bf586fab7409de43ce82bf8d9f7eb119536adc9783fd"}, - {file = "google_re2-1.1-3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d8140ca861cfe00602319cefe2c7b8737b379eb07fb328b51dc44584f47a2718"}, - {file = "google_re2-1.1-3-cp310-cp310-win32.whl", hash = "sha256:41f439c5c54e8a3a0a1fa2dbd1e809d3f643f862df7b16dd790f36a1238a272e"}, - {file = "google_re2-1.1-3-cp310-cp310-win_amd64.whl", hash = "sha256:fe20e97a33176d96d3e4b5b401de35182b9505823abea51425ec011f53ef5e56"}, - {file = "google_re2-1.1-3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c39ff52b1765db039f690ee5b7b23919d8535aae94db7996079fbde0098c4d7"}, - {file = "google_re2-1.1-3-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5420be674fd164041639ba4c825450f3d4bd635572acdde16b3dcd697f8aa3ef"}, - {file = "google_re2-1.1-3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:ff53881cf1ce040f102a42d39db93c3f835f522337ae9c79839a842f26d97733"}, - {file = "google_re2-1.1-3-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:8d04600b0b53523118df2e413a71417c408f20dee640bf07dfab601c96a18a77"}, - {file = "google_re2-1.1-3-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:c4835d4849faa34a7fa1074098d81c420ed6c0707a3772482b02ce14f2a7c007"}, - {file = "google_re2-1.1-3-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:3309a9b81251d35fee15974d0ae0581a9a375266deeafdc3a3ac0d172a742357"}, - {file = "google_re2-1.1-3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e2b51cafee7e0bc72d0a4a454547bd8f257cde412ac9f1a2dc46a203b5e42cf4"}, - {file = "google_re2-1.1-3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:83f5f1cb52f832c2297d271ee8c56cf5e9053448162e5d2223d513f729bad908"}, - {file = "google_re2-1.1-3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55865a1ace92be3f7953b2e2b38b901d8074a367aa491daee43260a53a7fc6f0"}, - {file = "google_re2-1.1-3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cec2167dd142e583e98c783bd0d28b8cf5a9cdbe1f7407ba4163fe3ccb613cb9"}, - {file = "google_re2-1.1-3-cp311-cp311-win32.whl", hash = "sha256:a0bc1fe96849e4eb8b726d0bba493f5b989372243b32fe20729cace02e5a214d"}, - {file = "google_re2-1.1-3-cp311-cp311-win_amd64.whl", hash = "sha256:e6310a156db96fc5957cb007dd2feb18476898654530683897469447df73a7cd"}, - {file = "google_re2-1.1-3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8e63cd10ea006088b320e8c5d308da1f6c87aa95138a71c60dd7ca1c8e91927e"}, - {file = "google_re2-1.1-3-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:12b566830a334178733a85e416b1e0507dbc0ceb322827616fe51ef56c5154f1"}, - {file = "google_re2-1.1-3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:442e18c9d46b225c1496919c16eafe8f8d9bb4091b00b4d3440da03c55bbf4ed"}, - {file = "google_re2-1.1-3-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:c54c00263a9c39b2dacd93e9636319af51e3cf885c080b9680a9631708326460"}, - {file = "google_re2-1.1-3-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:15a3caeeb327bc22e0c9f95eb76890fec8874cacccd2b01ff5c080ab4819bbec"}, - {file = "google_re2-1.1-3-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:59ec0d2cced77f715d41f6eafd901f6b15c11e28ba25fe0effdc1de554d78e75"}, - {file = "google_re2-1.1-3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:185bf0e3441aed3840590f8e42f916e2920d235eb14df2cbc2049526803d3e71"}, - {file = "google_re2-1.1-3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:586d3f2014eea5be14d8de53374d9b79fa99689160e00efa64b5fe93af326087"}, - {file = "google_re2-1.1-3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc2575082de4ffd234d9607f3ae67ca22b15a1a88793240e2045f3b3a36a5795"}, - {file = "google_re2-1.1-3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:59c5ad438eddb3630def394456091284d7bbc5b89351987f94f3792d296d1f96"}, - {file = "google_re2-1.1-3-cp312-cp312-win32.whl", hash = "sha256:5b9878c53f2bf16f75bf71d4ddd57f6611351408d5821040e91c53ebdf82c373"}, - {file = "google_re2-1.1-3-cp312-cp312-win_amd64.whl", hash = "sha256:4fdecfeb213110d0a85bad335a8e7cdb59fea7de81a4fe659233f487171980f9"}, - {file = "google_re2-1.1-3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2dd87bacab32b709c28d0145fe75a956b6a39e28f0726d867375dba5721c76c1"}, - {file = "google_re2-1.1-3-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:55d24c61fe35dddc1bb484593a57c9f60f9e66d7f31f091ef9608ed0b6dde79f"}, - {file = "google_re2-1.1-3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a0cf1180d908622df648c26b0cd09281f92129805ccc56a39227fdbfeab95cb4"}, - {file = "google_re2-1.1-3-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:09586f07f3f88d432265c75976da1c619ab7192cd7ebdf53f4ae0776c19e4b56"}, - {file = "google_re2-1.1-3-cp38-cp38-macosx_13_0_arm64.whl", hash = "sha256:539f1b053402203576e919a06749198da4ae415931ee28948a1898131ae932ce"}, - {file = "google_re2-1.1-3-cp38-cp38-macosx_13_0_x86_64.whl", hash = "sha256:abf0bcb5365b0e27a5a23f3da403dffdbbac2c0e3a3f1535a8b10cc121b5d5fb"}, - {file = "google_re2-1.1-3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:19c83e5bbed7958213eeac3aa71c506525ce54faf03e07d0b96cd0a764890511"}, - {file = "google_re2-1.1-3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3348e77330ff672dc44ec01894fa5d93c409a532b6d688feac55e714e9059920"}, - {file = "google_re2-1.1-3-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:06b63edb57c5ce5a13eabfd71155e346b9477dc8906dec7c580d4f70c16a7e0d"}, - {file = "google_re2-1.1-3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:12fe57ba2914092b83338d61d8def9ebd5a2bd0fd8679eceb5d4c2748105d5c0"}, - {file = "google_re2-1.1-3-cp38-cp38-win32.whl", hash = "sha256:80796e08d24e606e675019fe8de4eb5c94bb765be13c384f2695247d54a6df75"}, - {file = "google_re2-1.1-3-cp38-cp38-win_amd64.whl", hash = "sha256:3c2257dedfe7cc5deb6791e563af9e071a9d414dad89e37ac7ad22f91be171a9"}, - {file = "google_re2-1.1-3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43a0cd77c87c894f28969ac622f94b2e6d1571261dfdd785026848a25cfdc9b9"}, - {file = "google_re2-1.1-3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1038990b77fd66f279bd66a0832b67435ea925e15bb59eafc7b60fdec812b616"}, - {file = "google_re2-1.1-3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:fb5dda6875d18dd45f0f24ebced6d1f7388867c8fb04a235d1deab7ea479ce38"}, - {file = "google_re2-1.1-3-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:bb1d164965c6d57a351b421d2f77c051403766a8b75aaa602324ee2451fff77f"}, - {file = "google_re2-1.1-3-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:a072ebfa495051d07ffecbf6ce21eb84793568d5c3c678c00ed8ff6b8066ab31"}, - {file = "google_re2-1.1-3-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:4eb66c8398c8a510adc97978d944b3b29c91181237218841ea1a91dc39ec0e54"}, - {file = "google_re2-1.1-3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f7c8b57b1f559553248d1757b7fa5b2e0cc845666738d155dff1987c2618264e"}, - {file = "google_re2-1.1-3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9162f6aa4f25453c682eb176f21b8e2f40205be9f667e98a54b3e1ff10d6ee75"}, - {file = "google_re2-1.1-3-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2d65ddf67fd7bf94705626871d463057d3d9a3538d41022f95b9d8f01df36e1"}, - {file = "google_re2-1.1-3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d140c7b9395b4d1e654127aa1c99bcc603ed01000b7bc7e28c52562f1894ec12"}, - {file = "google_re2-1.1-3-cp39-cp39-win32.whl", hash = "sha256:80c5fc200f64b2d903eeb07b8d6cefc620a872a0240c7caaa9aca05b20f5568f"}, - {file = "google_re2-1.1-3-cp39-cp39-win_amd64.whl", hash = "sha256:9eb6dbcee9b5dc4069bbc0634f2eb039ca524a14bed5868fdf6560aaafcbca06"}, - {file = "google_re2-1.1-4-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0db114d7e1aa96dbcea452a40136d7d747d60cbb61394965774688ef59cccd4e"}, - {file = "google_re2-1.1-4-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:82133958e003a1344e5b7a791b9a9dd7560b5c8f96936dbe16f294604524a633"}, - {file = "google_re2-1.1-4-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:9e74fd441d1f3d917d3303e319f61b82cdbd96b9a5ba919377a6eef1504a1e2b"}, - {file = "google_re2-1.1-4-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:734a2e7a4541c57253b5ebee24f3f3366ba3658bcad01da25fb623c78723471a"}, - {file = "google_re2-1.1-4-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:d88d5eecbc908abe16132456fae13690d0508f3ac5777f320ef95cb6cab9a961"}, - {file = "google_re2-1.1-4-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:b91db80b171ecec435a07977a227757dd487356701a32f556fa6fca5d0a40522"}, - {file = "google_re2-1.1-4-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b23129887a64bb9948af14c84705273ed1a40054e99433b4acccab4dcf6a226"}, - {file = "google_re2-1.1-4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5dc1a0cc7cd19261dcaf76763e2499305dbb7e51dc69555167cdb8af98782698"}, - {file = "google_re2-1.1-4-cp310-cp310-win32.whl", hash = "sha256:3b2ab1e2420b5dd9743a2d6bc61b64e5f708563702a75b6db86637837eaeaf2f"}, - {file = "google_re2-1.1-4-cp310-cp310-win_amd64.whl", hash = "sha256:92efca1a7ef83b6df012d432a1cbc71d10ff42200640c0f9a5ff5b343a48e633"}, - {file = "google_re2-1.1-4-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:854818fd4ce79787aca5ba459d6e5abe4ca9be2c684a5b06a7f1757452ca3708"}, - {file = "google_re2-1.1-4-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:4ceef51174b6f653b6659a8fdaa9c38960c5228b44b25be2a3bcd8566827554f"}, - {file = "google_re2-1.1-4-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:ee49087c3db7e6f5238105ab5299c09e9b77516fe8cfb0a37e5f1e813d76ecb8"}, - {file = "google_re2-1.1-4-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:dc2312854bdc01410acc5d935f1906a49cb1f28980341c20a68797ad89d8e178"}, - {file = "google_re2-1.1-4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:0dc0d2e42296fa84a3cb3e1bd667c6969389cd5cdf0786e6b1f911ae2d75375b"}, - {file = "google_re2-1.1-4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6bf04ced98453b035f84320f348f67578024f44d2997498def149054eb860ae8"}, - {file = "google_re2-1.1-4-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d6b6ef11dc4ab322fa66c2f3561925f2b5372a879c3ed764d20e939e2fd3e5f"}, - {file = "google_re2-1.1-4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0dcde6646fa9a97fd3692b3f6ae7daf7f3277d7500b6c253badeefa11db8956a"}, - {file = "google_re2-1.1-4-cp311-cp311-win32.whl", hash = "sha256:5f4f0229deb057348893574d5b0a96d055abebac6debf29d95b0c0e26524c9f6"}, - {file = "google_re2-1.1-4-cp311-cp311-win_amd64.whl", hash = "sha256:4713ddbe48a18875270b36a462b0eada5e84d6826f8df7edd328d8706b6f9d07"}, - {file = "google_re2-1.1-4-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:40a698300b8faddbb325662973f839489c89b960087060bd389c376828978a04"}, - {file = "google_re2-1.1-4-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:103d2d7ac92ba23911a151fd1fc7035cbf6dc92a7f6aea92270ebceb5cd5acd3"}, - {file = "google_re2-1.1-4-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:51fb7182bccab05e8258a2b6a63dda1a6b4a9e8dfb9b03ec50e50c49c2827dd4"}, - {file = "google_re2-1.1-4-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:65383022abd63d7b620221eba7935132b53244b8b463d8fdce498c93cf58b7b7"}, - {file = "google_re2-1.1-4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:396281fc68a9337157b3ffcd9392c6b7fcb8aab43e5bdab496262a81d56a4ecc"}, - {file = "google_re2-1.1-4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:8198adcfcff1c680e052044124621730fc48d08005f90a75487f5651f1ebfce2"}, - {file = "google_re2-1.1-4-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:81f7bff07c448aec4db9ca453d2126ece8710dbd9278b8bb09642045d3402a96"}, - {file = "google_re2-1.1-4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7dacf730fd7d6ec71b11d6404b0b26e230814bfc8e9bb0d3f13bec9b5531f8d"}, - {file = "google_re2-1.1-4-cp312-cp312-win32.whl", hash = "sha256:8c764f62f4b1d89d1ef264853b6dd9fee14a89e9b86a81bc2157fe3531425eb4"}, - {file = "google_re2-1.1-4-cp312-cp312-win_amd64.whl", hash = "sha256:0be2666df4bc5381a5d693585f9bbfefb0bfd3c07530d7e403f181f5de47254a"}, - {file = "google_re2-1.1-4-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:5cb1b63a0bfd8dd65d39d2f3b2e5ae0a06ce4b2ce5818a1d1fc78a786a252673"}, - {file = "google_re2-1.1-4-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:e41751ce6b67a95230edd0772226dc94c2952a2909674cd69df9804ed0125307"}, - {file = "google_re2-1.1-4-cp38-cp38-macosx_13_0_arm64.whl", hash = "sha256:b998cfa2d50bf4c063e777c999a7e8645ec7e5d7baf43ad71b1e2e10bb0300c3"}, - {file = "google_re2-1.1-4-cp38-cp38-macosx_13_0_x86_64.whl", hash = "sha256:226ca3b0c2e970f3fc82001ac89e845ecc7a4bb7c68583e7a76cda70b61251a7"}, - {file = "google_re2-1.1-4-cp38-cp38-macosx_14_0_arm64.whl", hash = "sha256:9adec1f734ebad7c72e56c85f205a281d8fe9bf6583bc21020157d3f2812ce89"}, - {file = "google_re2-1.1-4-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:9c34f3c64ba566af967d29e11299560e6fdfacd8ca695120a7062b6ed993b179"}, - {file = "google_re2-1.1-4-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b85385fe293838e0d0b6e19e6c48ba8c6f739ea92ce2e23b718afe7b343363"}, - {file = "google_re2-1.1-4-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4694daa8a8987cfb568847aa872f9990e930c91a68c892ead876411d4b9012c3"}, - {file = "google_re2-1.1-4-cp38-cp38-win32.whl", hash = "sha256:5e671e9be1668187e2995aac378de574fa40df70bb6f04657af4d30a79274ce0"}, - {file = "google_re2-1.1-4-cp38-cp38-win_amd64.whl", hash = "sha256:f66c164d6049a8299f6dfcfa52d1580576b4b9724d6fcdad2f36f8f5da9304b6"}, - {file = "google_re2-1.1-4-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:25cb17ae0993a48c70596f3a3ef5d659638106401cc8193f51c0d7961b3b3eb7"}, - {file = "google_re2-1.1-4-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:5f101f86d14ca94ca4dcf63cceaa73d351f2be2481fcaa29d9e68eeab0dc2a88"}, - {file = "google_re2-1.1-4-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:4e82591e85bf262a6d74cff152867e05fc97867c68ba81d6836ff8b0e7e62365"}, - {file = "google_re2-1.1-4-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:1f61c09b93ffd34b1e2557e5a9565039f935407a5786dbad46f64f1a484166e6"}, - {file = "google_re2-1.1-4-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:12b390ad8c7e74bab068732f774e75e0680dade6469b249a721f3432f90edfc3"}, - {file = "google_re2-1.1-4-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:1284343eb31c2e82ed2d8159f33ba6842238a56782c881b07845a6d85613b055"}, - {file = "google_re2-1.1-4-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c7b38e0daf2c06e4d3163f4c732ab3ad2521aecfed6605b69e4482c612da303"}, - {file = "google_re2-1.1-4-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f4d4f0823e8b2f6952a145295b1ff25245ce9bb136aff6fe86452e507d4c1dd"}, - {file = "google_re2-1.1-4-cp39-cp39-win32.whl", hash = "sha256:1afae56b2a07bb48cfcfefaa15ed85bae26a68f5dc7f9e128e6e6ea36914e847"}, - {file = "google_re2-1.1-4-cp39-cp39-win_amd64.whl", hash = "sha256:aa7d6d05911ab9c8adbf3c225a7a120ab50fd2784ac48f2f0d140c0b7afc2b55"}, - {file = "google_re2-1.1-5-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:222fc2ee0e40522de0b21ad3bc90ab8983be3bf3cec3d349c80d76c8bb1a4beb"}, - {file = "google_re2-1.1-5-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:d4763b0b9195b72132a4e7de8e5a9bf1f05542f442a9115aa27cfc2a8004f581"}, - {file = "google_re2-1.1-5-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:209649da10c9d4a93d8a4d100ecbf9cc3b0252169426bec3e8b4ad7e57d600cf"}, - {file = "google_re2-1.1-5-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:68813aa333c1604a2df4a495b2a6ed065d7c8aebf26cc7e7abb5a6835d08353c"}, - {file = "google_re2-1.1-5-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:370a23ec775ad14e9d1e71474d56f381224dcf3e72b15d8ca7b4ad7dd9cd5853"}, - {file = "google_re2-1.1-5-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:14664a66a3ddf6bc9e56f401bf029db2d169982c53eff3f5876399104df0e9a6"}, - {file = "google_re2-1.1-5-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea3722cc4932cbcebd553b69dce1b4a73572823cff4e6a244f1c855da21d511"}, - {file = "google_re2-1.1-5-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e14bb264c40fd7c627ef5678e295370cd6ba95ca71d835798b6e37502fc4c690"}, - {file = "google_re2-1.1-5-cp310-cp310-win32.whl", hash = "sha256:39512cd0151ea4b3969c992579c79b423018b464624ae955be685fc07d94556c"}, - {file = "google_re2-1.1-5-cp310-cp310-win_amd64.whl", hash = "sha256:ac66537aa3bc5504320d922b73156909e3c2b6da19739c866502f7827b3f9fdf"}, - {file = "google_re2-1.1-5-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5b5ea68d54890c9edb1b930dcb2658819354e5d3f2201f811798bbc0a142c2b4"}, - {file = "google_re2-1.1-5-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:33443511b6b83c35242370908efe2e8e1e7cae749c766b2b247bf30e8616066c"}, - {file = "google_re2-1.1-5-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:413d77bdd5ba0bfcada428b4c146e87707452ec50a4091ec8e8ba1413d7e0619"}, - {file = "google_re2-1.1-5-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:5171686e43304996a34baa2abcee6f28b169806d0e583c16d55e5656b092a414"}, - {file = "google_re2-1.1-5-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b284db130283771558e31a02d8eb8fb756156ab98ce80035ae2e9e3a5f307c4"}, - {file = "google_re2-1.1-5-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:296e6aed0b169648dc4b870ff47bd34c702a32600adb9926154569ef51033f47"}, - {file = "google_re2-1.1-5-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:38d50e68ead374160b1e656bbb5d101f0b95fb4cc57f4a5c12100155001480c5"}, - {file = "google_re2-1.1-5-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a0416a35921e5041758948bcb882456916f22845f66a93bc25070ef7262b72a"}, - {file = "google_re2-1.1-5-cp311-cp311-win32.whl", hash = "sha256:a1d59568bbb5de5dd56dd6cdc79907db26cce63eb4429260300c65f43469e3e7"}, - {file = "google_re2-1.1-5-cp311-cp311-win_amd64.whl", hash = "sha256:72f5a2f179648b8358737b2b493549370debd7d389884a54d331619b285514e3"}, - {file = "google_re2-1.1-5-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:cbc72c45937b1dc5acac3560eb1720007dccca7c9879138ff874c7f6baf96005"}, - {file = "google_re2-1.1-5-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:5fadd1417fbef7235fa9453dba4eb102e6e7d94b1e4c99d5fa3dd4e288d0d2ae"}, - {file = "google_re2-1.1-5-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:040f85c63cc02696485b59b187a5ef044abe2f99b92b4fb399de40b7d2904ccc"}, - {file = "google_re2-1.1-5-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:64e3b975ee6d9bbb2420494e41f929c1a0de4bcc16d86619ab7a87f6ea80d6bd"}, - {file = "google_re2-1.1-5-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8ee370413e00f4d828eaed0e83b8af84d7a72e8ee4f4bd5d3078bc741dfc430a"}, - {file = "google_re2-1.1-5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:5b89383001079323f693ba592d7aad789d7a02e75adb5d3368d92b300f5963fd"}, - {file = "google_re2-1.1-5-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:63cb4fdfbbda16ae31b41a6388ea621510db82feb8217a74bf36552ecfcd50ad"}, - {file = "google_re2-1.1-5-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ebedd84ae8be10b7a71a16162376fd67a2386fe6361ef88c622dcf7fd679daf"}, - {file = "google_re2-1.1-5-cp312-cp312-win32.whl", hash = "sha256:c8e22d1692bc2c81173330c721aff53e47ffd3c4403ff0cd9d91adfd255dd150"}, - {file = "google_re2-1.1-5-cp312-cp312-win_amd64.whl", hash = "sha256:5197a6af438bb8c4abda0bbe9c4fbd6c27c159855b211098b29d51b73e4cbcf6"}, - {file = "google_re2-1.1-5-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:b6727e0b98417e114b92688ad2aa256102ece51f29b743db3d831df53faf1ce3"}, - {file = "google_re2-1.1-5-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:711e2b6417eb579c61a4951029d844f6b95b9b373b213232efd413659889a363"}, - {file = "google_re2-1.1-5-cp38-cp38-macosx_13_0_arm64.whl", hash = "sha256:71ae8b3df22c5c154c8af0f0e99d234a450ef1644393bc2d7f53fc8c0a1e111c"}, - {file = "google_re2-1.1-5-cp38-cp38-macosx_13_0_x86_64.whl", hash = "sha256:94a04e214bc521a3807c217d50cf099bbdd0c0a80d2d996c0741dbb995b5f49f"}, - {file = "google_re2-1.1-5-cp38-cp38-macosx_14_0_arm64.whl", hash = "sha256:a770f75358508a9110c81a1257721f70c15d9bb592a2fb5c25ecbd13566e52a5"}, - {file = "google_re2-1.1-5-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:07c9133357f7e0b17c6694d5dcb82e0371f695d7c25faef2ff8117ef375343ff"}, - {file = "google_re2-1.1-5-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:204ca6b1cf2021548f4a9c29ac015e0a4ab0a7b6582bf2183d838132b60c8fda"}, - {file = "google_re2-1.1-5-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0b95857c2c654f419ca684ec38c9c3325c24e6ba7d11910a5110775a557bb18"}, - {file = "google_re2-1.1-5-cp38-cp38-win32.whl", hash = "sha256:347ac770e091a0364e822220f8d26ab53e6fdcdeaec635052000845c5a3fb869"}, - {file = "google_re2-1.1-5-cp38-cp38-win_amd64.whl", hash = "sha256:ec32bb6de7ffb112a07d210cf9f797b7600645c2d5910703fa07f456dd2150e0"}, - {file = "google_re2-1.1-5-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:eb5adf89060f81c5ff26c28e261e6b4997530a923a6093c9726b8dec02a9a326"}, - {file = "google_re2-1.1-5-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:a22630c9dd9ceb41ca4316bccba2643a8b1d5c198f21c00ed5b50a94313aaf10"}, - {file = "google_re2-1.1-5-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:544dc17fcc2d43ec05f317366375796351dec44058e1164e03c3f7d050284d58"}, - {file = "google_re2-1.1-5-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:19710af5ea88751c7768575b23765ce0dfef7324d2539de576f75cdc319d6654"}, - {file = "google_re2-1.1-5-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:f82995a205e08ad896f4bd5ce4847c834fab877e1772a44e5f262a647d8a1dec"}, - {file = "google_re2-1.1-5-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:63533c4d58da9dc4bc040250f1f52b089911699f0368e0e6e15f996387a984ed"}, - {file = "google_re2-1.1-5-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:79e00fcf0cb04ea35a22b9014712d448725ce4ddc9f08cc818322566176ca4b0"}, - {file = "google_re2-1.1-5-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bc41afcefee2da6c4ed883a93d7f527c4b960cd1d26bbb0020a7b8c2d341a60a"}, - {file = "google_re2-1.1-5-cp39-cp39-win32.whl", hash = "sha256:486730b5e1f1c31b0abc6d80abe174ce4f1188fe17d1b50698f2bf79dc6e44be"}, - {file = "google_re2-1.1-5-cp39-cp39-win_amd64.whl", hash = "sha256:4de637ca328f1d23209e80967d1b987d6b352cd01b3a52a84b4d742c69c3da6c"}, - {file = "google_re2-1.1-6-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:621e9c199d1ff0fdb2a068ad450111a84b3bf14f96dfe5a8a7a0deae5f3f4cce"}, - {file = "google_re2-1.1-6-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:220acd31e7dde95373f97c3d1f3b3bd2532b38936af28b1917ee265d25bebbf4"}, - {file = "google_re2-1.1-6-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:db34e1098d164f76251a6ece30e8f0ddfd65bb658619f48613ce71acb3f9cbdb"}, - {file = "google_re2-1.1-6-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:5152bac41d8073977582f06257219541d0fc46ad99b0bbf30e8f60198a43b08c"}, - {file = "google_re2-1.1-6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:6191294799e373ee1735af91f55abd23b786bdfd270768a690d9d55af9ea1b0d"}, - {file = "google_re2-1.1-6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:070cbafbb4fecbb02e98feb28a1eb292fb880f434d531f38cc33ee314b521f1f"}, - {file = "google_re2-1.1-6-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8437d078b405a59a576cbed544490fe041140f64411f2d91012e8ec05ab8bf86"}, - {file = "google_re2-1.1-6-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f00f9a9af8896040e37896d9b9fc409ad4979f1ddd85bb188694a7d95ddd1164"}, - {file = "google_re2-1.1-6-cp310-cp310-win32.whl", hash = "sha256:df26345f229a898b4fd3cafd5f82259869388cee6268fc35af16a8e2293dd4e5"}, - {file = "google_re2-1.1-6-cp310-cp310-win_amd64.whl", hash = "sha256:3665d08262c57c9b28a5bdeb88632ad792c4e5f417e5645901695ab2624f5059"}, - {file = "google_re2-1.1-6-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:b26b869d8aa1d8fe67c42836bf3416bb72f444528ee2431cfb59c0d3e02c6ce3"}, - {file = "google_re2-1.1-6-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:41fd4486c57dea4f222a6bb7f1ff79accf76676a73bdb8da0fcbd5ba73f8da71"}, - {file = "google_re2-1.1-6-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:0ee378e2e74e25960070c338c28192377c4dd41e7f4608f2688064bd2badc41e"}, - {file = "google_re2-1.1-6-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:a00cdbf662693367b36d075b29feb649fd7ee1b617cf84f85f2deebeda25fc64"}, - {file = "google_re2-1.1-6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4c09455014217a41499432b8c8f792f25f3df0ea2982203c3a8c8ca0e7895e69"}, - {file = "google_re2-1.1-6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6501717909185327935c7945e23bb5aa8fc7b6f237b45fe3647fa36148662158"}, - {file = "google_re2-1.1-6-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3510b04790355f199e7861c29234081900e1e1cbf2d1484da48aa0ba6d7356ab"}, - {file = "google_re2-1.1-6-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8c0e64c187ca406764f9e9ad6e750d62e69ed8f75bf2e865d0bfbc03b642361c"}, - {file = "google_re2-1.1-6-cp311-cp311-win32.whl", hash = "sha256:2a199132350542b0de0f31acbb3ca87c3a90895d1d6e5235f7792bb0af02e523"}, - {file = "google_re2-1.1-6-cp311-cp311-win_amd64.whl", hash = "sha256:83bdac8ceaece8a6db082ea3a8ba6a99a2a1ee7e9f01a9d6d50f79c6f251a01d"}, - {file = "google_re2-1.1-6-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:81985ff894cd45ab5a73025922ac28c0707759db8171dd2f2cc7a0e856b6b5ad"}, - {file = "google_re2-1.1-6-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:5635af26065e6b45456ccbea08674ae2ab62494008d9202df628df3b267bc095"}, - {file = "google_re2-1.1-6-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:813b6f04de79f4a8fdfe05e2cb33e0ccb40fe75d30ba441d519168f9d958bd54"}, - {file = "google_re2-1.1-6-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:5ec2f5332ad4fd232c3f2d6748c2c7845ccb66156a87df73abcc07f895d62ead"}, - {file = "google_re2-1.1-6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5a687b3b32a6cbb731647393b7c4e3fde244aa557f647df124ff83fb9b93e170"}, - {file = "google_re2-1.1-6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:39a62f9b3db5d3021a09a47f5b91708b64a0580193e5352751eb0c689e4ad3d7"}, - {file = "google_re2-1.1-6-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ca0f0b45d4a1709cbf5d21f355e5809ac238f1ee594625a1e5ffa9ff7a09eb2b"}, - {file = "google_re2-1.1-6-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a64b3796a7a616c7861247bd061c9a836b5caf0d5963e5ea8022125601cf7b09"}, - {file = "google_re2-1.1-6-cp312-cp312-win32.whl", hash = "sha256:32783b9cb88469ba4cd9472d459fe4865280a6b1acdad4480a7b5081144c4eb7"}, - {file = "google_re2-1.1-6-cp312-cp312-win_amd64.whl", hash = "sha256:259ff3fd2d39035b9cbcbf375995f83fa5d9e6a0c5b94406ff1cc168ed41d6c6"}, - {file = "google_re2-1.1-6-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:e4711bcffe190acd29104d8ecfea0c0e42b754837de3fb8aad96e6cc3c613cdc"}, - {file = "google_re2-1.1-6-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:4d081cce43f39c2e813fe5990e1e378cbdb579d3f66ded5bade96130269ffd75"}, - {file = "google_re2-1.1-6-cp38-cp38-macosx_13_0_arm64.whl", hash = "sha256:4f123b54d48450d2d6b14d8fad38e930fb65b5b84f1b022c10f2913bd956f5b5"}, - {file = "google_re2-1.1-6-cp38-cp38-macosx_13_0_x86_64.whl", hash = "sha256:e1928b304a2b591a28eb3175f9db7f17c40c12cf2d4ec2a85fdf1cc9c073ff91"}, - {file = "google_re2-1.1-6-cp38-cp38-macosx_14_0_arm64.whl", hash = "sha256:3a69f76146166aec1173003c1f547931bdf288c6b135fda0020468492ac4149f"}, - {file = "google_re2-1.1-6-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:fc08c388f4ebbbca345e84a0c56362180d33d11cbe9ccfae663e4db88e13751e"}, - {file = "google_re2-1.1-6-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b057adf38ce4e616486922f2f47fc7d19c827ba0a7f69d540a3664eba2269325"}, - {file = "google_re2-1.1-6-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4138c0b933ab099e96f5d8defce4486f7dfd480ecaf7f221f2409f28022ccbc5"}, - {file = "google_re2-1.1-6-cp38-cp38-win32.whl", hash = "sha256:9693e45b37b504634b1abbf1ee979471ac6a70a0035954592af616306ab05dd6"}, - {file = "google_re2-1.1-6-cp38-cp38-win_amd64.whl", hash = "sha256:5674d437baba0ea287a5a7f8f81f24265d6ae8f8c09384e2ef7b6f84b40a7826"}, - {file = "google_re2-1.1-6-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:7783137cb2e04f458a530c6d0ee9ef114815c1d48b9102f023998c371a3b060e"}, - {file = "google_re2-1.1-6-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:a49b7153935e7a303675f4deb5f5d02ab1305adefc436071348706d147c889e0"}, - {file = "google_re2-1.1-6-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:a96a8bb309182090704593c60bdb369a2756b38fe358bbf0d40ddeb99c71769f"}, - {file = "google_re2-1.1-6-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:dff3d4be9f27ef8ec3705eed54f19ef4ab096f5876c15fe011628c69ba3b561c"}, - {file = "google_re2-1.1-6-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:40f818b0b39e26811fa677978112a8108269977fdab2ba0453ac4363c35d9e66"}, - {file = "google_re2-1.1-6-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:8a7e53538cdb40ef4296017acfbb05cab0c19998be7552db1cfb85ba40b171b9"}, - {file = "google_re2-1.1-6-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ee18e7569fb714e5bb8c42809bf8160738637a5e71ed5a4797757a1fb4dc4de"}, - {file = "google_re2-1.1-6-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1cda4f6d1a7d5b43ea92bc395f23853fba0caf8b1e1efa6e8c48685f912fcb89"}, - {file = "google_re2-1.1-6-cp39-cp39-win32.whl", hash = "sha256:6a9cdbdc36a2bf24f897be6a6c85125876dc26fea9eb4247234aec0decbdccfd"}, - {file = "google_re2-1.1-6-cp39-cp39-win_amd64.whl", hash = "sha256:73f646cecfad7cc5b4330b4192c25f2e29730a3b8408e089ffd2078094208196"}, + {file = "google_re2-1.1.20240702-1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:46e7ed614ffaafccae017542d68e9bbf664c8c1e5ca37046adee640bbee4846e"}, + {file = "google_re2-1.1.20240702-1-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:3c8d2c0a03e9fd24f78b624cf7e40ac32aaf4837fda7339e2c22ca42e3dca512"}, + {file = "google_re2-1.1.20240702-1-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:7fee39772aa2e1fe91b7694acc48888ac6fa0ca51f8805464272a2089b362c96"}, + {file = "google_re2-1.1.20240702-1-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:b2bcf1a43853cee5a088f40c75fe48a6e3ec7addae1d3f3d47ce679e2bb8936b"}, + {file = "google_re2-1.1.20240702-1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:69f9b156de6f93ea00844f6cd4f2ed5124f9f01692da7ae0fe9a9516df6c63c2"}, + {file = "google_re2-1.1.20240702-1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:f70db559ad768ad68a4d9897cb19fd13f7761e60208f475eb8a69b8aa4b6df20"}, + {file = "google_re2-1.1.20240702-1-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7bc4fa65ecec3d63ea6048ecaf8784560bbfb31191c02ffaa87771e4a2f813e1"}, + {file = "google_re2-1.1.20240702-1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7480309b133c39f2afb19ff28bc30d27b364cbc56b5d46918d1b4f1fb2e13183"}, + {file = "google_re2-1.1.20240702-1-cp310-cp310-win32.whl", hash = "sha256:1950f499b277789267afee1755394cd959898d0b192b7052bb3186000aff27de"}, + {file = "google_re2-1.1.20240702-1-cp310-cp310-win_amd64.whl", hash = "sha256:2269ff8c2e1de0ee77736bd9f65b5c9f7cd43544eff825dc7b4ab2bf1f1901e4"}, + {file = "google_re2-1.1.20240702-1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:9802a5a5ec585048300d5a8ec522b15057b8f758fe9f8b0ec65ac2927a36a1aa"}, + {file = "google_re2-1.1.20240702-1-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:757cbefbe9f998c274c94afd8bf2a4789b983287f33d4f975389c1027ed686c6"}, + {file = "google_re2-1.1.20240702-1-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:7e1d36bd20ce04c1198fe482b6f3ce7dd699e1276946a9a2cf31b2e53026a370"}, + {file = "google_re2-1.1.20240702-1-cp311-cp311-macosx_13_0_x86_64.whl", hash = "sha256:bb6b2e456cd0002700ad58c3474fc9e342853ff2ef9f95a1f6606c819ffaf3d9"}, + {file = "google_re2-1.1.20240702-1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:71a71d7f9e616d3067e913a1432111593ee41aab2e0ed21ecbcf039451b9d899"}, + {file = "google_re2-1.1.20240702-1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:16bd5389baeb98936fb05926e6a38826c473206c13f1f789f7643a29dcccccc3"}, + {file = "google_re2-1.1.20240702-1-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4b920c1b0356f0359b35a0e6d0b5ff12fba9067d3c455a9811952fbc9a213268"}, + {file = "google_re2-1.1.20240702-1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42c2c39b7378e928d197e4fdf4a23c9338f29cad6d4c5c5c06a2ad7c8c2a3ebc"}, + {file = "google_re2-1.1.20240702-1-cp311-cp311-win32.whl", hash = "sha256:d7fd6b6be4f86d4b6503689b492970920f4b50a8ac02427bc975c73bcedda374"}, + {file = "google_re2-1.1.20240702-1-cp311-cp311-win_amd64.whl", hash = "sha256:22217d7c8f57bb6c5e74e171a510b12cdde4eddc2528f89aa0f50e3fc10fe17e"}, + {file = "google_re2-1.1.20240702-1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:00dcb09b15f92b490ae52f328cca229de2a157c8748f10df94dfea7637d32617"}, + {file = "google_re2-1.1.20240702-1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:2ffc6fbe70ccf9fb66d0ab16ccad0f661031ceb0eec3d73d170cd782a93d62d5"}, + {file = "google_re2-1.1.20240702-1-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:652e517b6db6cbf7403bab370940718208b15e811fefe7635d4e78a8037f096b"}, + {file = "google_re2-1.1.20240702-1-cp312-cp312-macosx_13_0_x86_64.whl", hash = "sha256:449ae8286d644d24af8a6eb81eeba6995388581739920b80d9e4b063eefe0322"}, + {file = "google_re2-1.1.20240702-1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:40568559b0a10240c10377fb5cdd46c9115da8a627c567db68c4dc29103a2ce9"}, + {file = "google_re2-1.1.20240702-1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:8139df33d61aac335726b6f32108e763ba2932569c63d2b3ebf6e36a40449223"}, + {file = "google_re2-1.1.20240702-1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e4a2b88516b4140891a014c6e5b774f57db90c8bd0ccf0554e9f9b99ee1e942"}, + {file = "google_re2-1.1.20240702-1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d95b1e06298299b28e23288a6bfd3c6f13e0f7a01c1f2e86e74073928676cf88"}, + {file = "google_re2-1.1.20240702-1-cp312-cp312-win32.whl", hash = "sha256:fb025d4bcd1a3032546da048a6dcb39359967f4df6b3514e76e983256235f694"}, + {file = "google_re2-1.1.20240702-1-cp312-cp312-win_amd64.whl", hash = "sha256:a7e3129d31e12d51397d603adf45bd696135a5d9d61bc33643bc5d2e4366070b"}, + {file = "google_re2-1.1.20240702-1-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:bc2f853ace690fb475f68b82b61e3b0ffe2a8603f052853eb21587ac7dcca537"}, + {file = "google_re2-1.1.20240702-1-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:974ac711ade3171004e9552d9e069cbe1a8de02c5e45a56101f8396f69a3e3c2"}, + {file = "google_re2-1.1.20240702-1-cp38-cp38-macosx_13_0_arm64.whl", hash = "sha256:ad3dc0084cad59a298ffa52c9def2f1b5332d396d76f3828237ac7141b6e7e7d"}, + {file = "google_re2-1.1.20240702-1-cp38-cp38-macosx_13_0_x86_64.whl", hash = "sha256:4e13241b8df4096d840f98993f39c62cff0cdab9d06c86b156d2944cfb3f0814"}, + {file = "google_re2-1.1.20240702-1-cp38-cp38-macosx_14_0_arm64.whl", hash = "sha256:6887fe9c291ad42003ad84e11c0a6fac0169adbda9cbc898b8657610512e4ce5"}, + {file = "google_re2-1.1.20240702-1-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:82824fa71f51a269cd9bad653d53e6ba5bee9095da059455ee1c6cc7e4ba014b"}, + {file = "google_re2-1.1.20240702-1-cp38-cp38-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cde1453681c2ab1648b9e7aed3861ccedce52c85b24873edd1ec1e92b4b3d7d4"}, + {file = "google_re2-1.1.20240702-1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7388c5aadcc5489291d2804ecc384c2e3bb64832e1b46afd44d7bca6c948b615"}, + {file = "google_re2-1.1.20240702-1-cp38-cp38-win32.whl", hash = "sha256:cb20853af1104b5180eb2daea66a481723553aa66bf5a5c4c58420c7369364cb"}, + {file = "google_re2-1.1.20240702-1-cp38-cp38-win_amd64.whl", hash = "sha256:a7f0d950ba9508ac1b2d89837f4a4c74092ae3af015a9797b80570ee87b7d7d5"}, + {file = "google_re2-1.1.20240702-1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:56c2a97d3d38345939fb3ff02d154f5c6ec929e0765723cfd390720f581d2581"}, + {file = "google_re2-1.1.20240702-1-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:dfe657979ab96da72f55b03ecdede5467a7193266ce7a0b85013819f052d231f"}, + {file = "google_re2-1.1.20240702-1-cp39-cp39-macosx_13_0_arm64.whl", hash = "sha256:c6e218b831dfc89f5004c1bb7ae9182ec5ddc4d46e6035f636ba96344d5b7478"}, + {file = "google_re2-1.1.20240702-1-cp39-cp39-macosx_13_0_x86_64.whl", hash = "sha256:304ed3f740541742e7ef5c162b36619efdac7345f1429ab6d70aefaae9a5658d"}, + {file = "google_re2-1.1.20240702-1-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:05f5683e1bcfac8adcc0dbfe3ecb0866cec6eea2c7d419271dfd72930b368ce4"}, + {file = "google_re2-1.1.20240702-1-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:39c642041428efaa48f35adf4475a014ce272f87a453c6dff68f2b05793d516f"}, + {file = "google_re2-1.1.20240702-1-cp39-cp39-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d3d1e58f374510101273cda1b6c2b45c178eb94f4c1bd17f7f750cea8d1c85a"}, + {file = "google_re2-1.1.20240702-1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:386d2a8c4b10daaeda03adc7f65c457f67ee8cb18b4f9b4178a44ed62ab291df"}, + {file = "google_re2-1.1.20240702-1-cp39-cp39-win32.whl", hash = "sha256:f853c3c68bed0d127e6ef8b29ee85461d9d0a4fa407e3f97e41ecd6803d24d88"}, + {file = "google_re2-1.1.20240702-1-cp39-cp39-win_amd64.whl", hash = "sha256:5e35c8db1bf58ddf1ac28782d6dca5894a0331fc0d33b2a2ce6eb59234d74312"}, + {file = "google_re2-1.1.20240702.tar.gz", hash = "sha256:8788db69f6c93cb229df62c74b2d9aa8e64bf754e9495700f85812afa32efd2b"}, ] [[package]] name = "googleapis-common-protos" -version = "1.60.0" +version = "1.65.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis-common-protos-1.60.0.tar.gz", hash = "sha256:e73ebb404098db405ba95d1e1ae0aa91c3e15a71da031a2eeb6b2e23e7bc3708"}, - {file = "googleapis_common_protos-1.60.0-py2.py3-none-any.whl", hash = "sha256:69f9bbcc6acde92cab2db95ce30a70bd2b81d20b12eff3f1aabaffcbe8a93918"}, + {file = "googleapis_common_protos-1.65.0-py2.py3-none-any.whl", hash = "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63"}, + {file = "googleapis_common_protos-1.65.0.tar.gz", hash = "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0"}, ] [package.dependencies] -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<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,<5.0.0.dev0" +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,<6.0.0.dev0" [package.extras] grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] @@ -1917,13 +1704,13 @@ dev = ["black", "pytest"] [[package]] name = "identify" -version = "2.5.26" +version = "2.6.1" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.26-py2.py3-none-any.whl", hash = "sha256:c22a8ead0d4ca11f1edd6c9418c3220669b3b7533ada0a0ffa6cc0ef85cf9b54"}, - {file = "identify-2.5.26.tar.gz", hash = "sha256:7243800bce2f58404ed41b7c002e53d4d22bcf3ae1b7900c2d7aefd95394bf7f"}, + {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, + {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, ] [package.extras] @@ -1931,15 +1718,18 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.7" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "inflect" version = "5.6.2" @@ -2005,20 +1795,17 @@ files = [ [[package]] name = "isort" -version = "5.12.0" +version = "5.13.2" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.8.0" files = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, ] [package.extras] -colors = ["colorama (>=0.4.3)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] +colors = ["colorama (>=0.4.6)"] [[package]] name = "itypes" @@ -2121,91 +1908,90 @@ pyasn1 = ">=0.4.6" [[package]] name = "markupsafe" -version = "2.1.3" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] name = "marshmallow" -version = "3.20.1" +version = "3.22.0" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.8" files = [ - {file = "marshmallow-3.20.1-py3-none-any.whl", hash = "sha256:684939db93e80ad3561392f47be0230743131560a41c5110684c16e21ade0a5c"}, - {file = "marshmallow-3.20.1.tar.gz", hash = "sha256:5d2371bbe42000f2b3fb5eaa065224df7d8f8597bc19a1bbfa5bfe7fba8da889"}, + {file = "marshmallow-3.22.0-py3-none-any.whl", hash = "sha256:71a2dce49ef901c3f97ed296ae5051135fd3febd2bf43afe0ae9a82143a494d9"}, + {file = "marshmallow-3.22.0.tar.gz", hash = "sha256:4972f529104a220bb8637d595aa4c9762afbe7f7a77d82dc58c1615d70c5823e"}, ] [package.dependencies] packaging = ">=17.0" [package.extras] -dev = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] -docs = ["alabaster (==0.7.13)", "autodocsumm (==0.2.11)", "sphinx (==7.0.1)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] -lint = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)"] +dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] +docs = ["alabaster (==1.0.0)", "autodocsumm (==0.2.13)", "sphinx (==8.0.2)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"] tests = ["pytest", "pytz", "simplejson"] [[package]] @@ -2232,13 +2018,13 @@ files = [ [[package]] name = "moto" -version = "4.1.14" +version = "4.1.15" description = "" optional = false python-versions = ">=3.7" files = [ - {file = "moto-4.1.14-py2.py3-none-any.whl", hash = "sha256:7d3bd748a34641715ba469c761f72fb8ec18f349987c98f5a0f9be85a07a9911"}, - {file = "moto-4.1.14.tar.gz", hash = "sha256:545afeb4df94dfa730e2d7e87366dc26b4a33c2891f462cbb049f040c80ed1ec"}, + {file = "moto-4.1.15-py2.py3-none-any.whl", hash = "sha256:3fbcf91090692c30117d275fb34b48a075a6f65d4712ba6c4d004ffab976db46"}, + {file = "moto-4.1.15.tar.gz", hash = "sha256:272236d312457b324c645741ee589924fd61a96b84680dc2e607f8663c563551"}, ] [package.dependencies] @@ -2270,6 +2056,7 @@ efs = ["sshpubkeys (>=3.1.0)"] eks = ["sshpubkeys (>=3.1.0)"] glue = ["pyparsing (>=3.0.7)"] iotdata = ["jsondiff (>=1.1.2)"] +resourcegroupstaggingapi = ["PyYAML (>=5.1)", "cfn-lint (>=0.40.0)", "docker (>=3.0.0)", "ecdsa (!=0.15)", "graphql-core", "jsondiff (>=1.1.2)", "openapi-spec-validator (>=0.2.8)", "py-partiql-parser (==0.3.6)", "pyparsing (>=3.0.7)", "python-jose[cryptography] (>=3.1.0,<4.0.0)", "sshpubkeys (>=3.1.0)"] route53resolver = ["sshpubkeys (>=3.1.0)"] s3 = ["PyYAML (>=5.1)", "py-partiql-parser (==0.3.6)"] s3crc32c = ["PyYAML (>=5.1)", "crc32c", "py-partiql-parser (==0.3.6)"] @@ -2279,50 +2066,47 @@ xray = ["aws-xray-sdk (>=0.93,!=0.96)", "setuptools"] [[package]] name = "msal" -version = "1.28.0" +version = "1.31.0" description = "The Microsoft Authentication Library (MSAL) for Python library enables your app to access the Microsoft Cloud by supporting authentication of users with Microsoft Azure Active Directory accounts (AAD) and Microsoft Accounts (MSA) using industry standard OAuth2 and OpenID Connect." optional = false python-versions = ">=3.7" files = [ - {file = "msal-1.28.0-py3-none-any.whl", hash = "sha256:3064f80221a21cd535ad8c3fafbb3a3582cd9c7e9af0bb789ae14f726a0ca99b"}, - {file = "msal-1.28.0.tar.gz", hash = "sha256:80bbabe34567cb734efd2ec1869b2d98195c927455369d8077b3c542088c5c9d"}, + {file = "msal-1.31.0-py3-none-any.whl", hash = "sha256:96bc37cff82ebe4b160d5fc0f1196f6ca8b50e274ecd0ec5bf69c438514086e7"}, + {file = "msal-1.31.0.tar.gz", hash = "sha256:2c4f189cf9cc8f00c80045f66d39b7c0f3ed45873fd3d1f2af9f22db2e12ff4b"}, ] [package.dependencies] -cryptography = ">=0.6,<45" +cryptography = ">=2.5,<46" PyJWT = {version = ">=1.0.0,<3", extras = ["crypto"]} requests = ">=2.0.0,<3" [package.extras] -broker = ["pymsalruntime (>=0.13.2,<0.15)"] +broker = ["pymsalruntime (>=0.14,<0.18)", "pymsalruntime (>=0.17,<0.18)"] [[package]] name = "msal-extensions" -version = "1.0.0" +version = "1.2.0" description = "Microsoft Authentication Library extensions (MSAL EX) provides a persistence API that can save your data on disk, encrypted on Windows, macOS and Linux. Concurrent data access will be coordinated by a file lock mechanism." optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "msal-extensions-1.0.0.tar.gz", hash = "sha256:c676aba56b0cce3783de1b5c5ecfe828db998167875126ca4b47dc6436451354"}, - {file = "msal_extensions-1.0.0-py2.py3-none-any.whl", hash = "sha256:91e3db9620b822d0ed2b4d1850056a0f133cba04455e62f11612e40f5502f2ee"}, + {file = "msal_extensions-1.2.0-py3-none-any.whl", hash = "sha256:cf5ba83a2113fa6dc011a254a72f1c223c88d7dfad74cc30617c4679a417704d"}, + {file = "msal_extensions-1.2.0.tar.gz", hash = "sha256:6f41b320bfd2933d631a215c91ca0dd3e67d84bd1a2f50ce917d5874ec646bef"}, ] [package.dependencies] -msal = ">=0.4.1,<2.0.0" -portalocker = [ - {version = ">=1.0,<3", markers = "python_version >= \"3.5\" and platform_system != \"Windows\""}, - {version = ">=1.6,<3", markers = "python_version >= \"3.5\" and platform_system == \"Windows\""}, -] +msal = ">=1.29,<2" +portalocker = ">=1.4,<3" [[package]] name = "mypy-boto3-dynamodb" -version = "1.33.0" -description = "Type annotations for boto3.DynamoDB 1.33.0 service generated with mypy-boto3-builder 7.20.3" +version = "1.35.24" +description = "Type annotations for boto3.DynamoDB 1.35.24 service generated with mypy-boto3-builder 8.1.1" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "mypy-boto3-dynamodb-1.33.0.tar.gz", hash = "sha256:2cfe1089c89de61b1ec0e69a72ba3e6865a013ea0a37d318ab564983785d42f9"}, - {file = "mypy_boto3_dynamodb-1.33.0-py3-none-any.whl", hash = "sha256:619ea2cc311ced0ecb44b6e8d3bf3dd851fb7c53a34128b4ff6d6e6a11fdd41f"}, + {file = "mypy_boto3_dynamodb-1.35.24-py3-none-any.whl", hash = "sha256:022859543c5314f14fb03ef4e445e34b97b9bc0cecb003c14c10943a2eaa3ff7"}, + {file = "mypy_boto3_dynamodb-1.35.24.tar.gz", hash = "sha256:55bf897a1d0e354579edb05001f4bc4f472b9452badd9db24876c31bdf3f72a1"}, ] [package.dependencies] @@ -2341,18 +2125,15 @@ files = [ [[package]] name = "nodeenv" -version = "1.8.0" +version = "1.9.1" description = "Node.js virtual environment builder" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, - {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, ] -[package.dependencies] -setuptools = "*" - [[package]] name = "oauth2client" version = "4.1.3" @@ -2389,18 +2170,19 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] [[package]] name = "opencensus" -version = "0.11.2" +version = "0.11.4" description = "A stats collection and distributed tracing framework" optional = false python-versions = "*" files = [ - {file = "opencensus-0.11.2-py2.py3-none-any.whl", hash = "sha256:7a1a34b87c8db3d9984e97ff05739058342f24de1d700766d59044eee8fb3b3f"}, - {file = "opencensus-0.11.2.tar.gz", hash = "sha256:6154042a236b9ecdd55a23dfbb2743bb3deacd0687e3e0391ec2e0c74950d66f"}, + {file = "opencensus-0.11.4-py2.py3-none-any.whl", hash = "sha256:a18487ce68bc19900336e0ff4655c5a116daf10c1b3685ece8d971bddad6a864"}, + {file = "opencensus-0.11.4.tar.gz", hash = "sha256:cbef87d8b8773064ab60e5c2a1ced58bbaa38a6d052c41aec224958ce544eff2"}, ] [package.dependencies] google-api-core = {version = ">=1.0.0,<3.0.0", markers = "python_version >= \"3.6\""} opencensus-context = ">=0.1.3" +six = ">=1.16,<2.0" [[package]] name = "opencensus-context" @@ -2415,19 +2197,19 @@ files = [ [[package]] name = "opencensus-ext-azure" -version = "1.1.9" +version = "1.1.13" description = "OpenCensus Azure Monitor Exporter" optional = false python-versions = "*" files = [ - {file = "opencensus-ext-azure-1.1.9.tar.gz", hash = "sha256:507608b77e9d8eaab6ffd5ff11b7ceb87f54e4a6a940c4b814331b4d1b034151"}, - {file = "opencensus_ext_azure-1.1.9-py2.py3-none-any.whl", hash = "sha256:166c858e70fb7b39d01ff7d9f745588c521070ff2cfe177f77b63ee87f5076ac"}, + {file = "opencensus-ext-azure-1.1.13.tar.gz", hash = "sha256:aec30472177005379ba56a702a097d618c5f57558e1bb6676ec75f948130692a"}, + {file = "opencensus_ext_azure-1.1.13-py2.py3-none-any.whl", hash = "sha256:06001fac6f8588ba00726a3a7c6c7f2fc88bc8ad12a65afdca657923085393dd"}, ] [package.dependencies] azure-core = ">=1.12.0,<2.0.0" azure-identity = ">=1.5.0,<2.0.0" -opencensus = ">=0.11.2,<1.0.0" +opencensus = ">=0.11.4,<1.0.0" psutil = ">=5.6.3" requests = ">=2.19.0" @@ -2459,13 +2241,13 @@ files = [ [[package]] name = "pathspec" -version = "0.11.2" +version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] [[package]] @@ -2501,28 +2283,29 @@ files = [ [[package]] name = "platformdirs" -version = "3.10.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, - {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" -version = "1.2.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, - {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] @@ -2531,13 +2314,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "portalocker" -version = "2.7.0" +version = "2.10.1" description = "Wraps the portalocker recipe for easy usage" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" files = [ - {file = "portalocker-2.7.0-py2.py3-none-any.whl", hash = "sha256:a07c5b4f3985c3cf4798369631fb7011adb498e2a46d8440efc75a8f29a0f983"}, - {file = "portalocker-2.7.0.tar.gz", hash = "sha256:032e81d534a88ec1736d03f780ba073f047a06c478b06e2937486f334e955c51"}, + {file = "portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf"}, + {file = "portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f"}, ] [package.dependencies] @@ -2546,7 +2329,7 @@ pywin32 = {version = ">=226", markers = "platform_system == \"Windows\""} [package.extras] docs = ["sphinx (>=1.7.1)"] redis = ["redis"] -tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "pytest-timeout (>=2.1.0)", "redis", "sphinx (>=6.0.0)"] +tests = ["pytest (>=5.4.1)", "pytest-cov (>=2.8.1)", "pytest-mypy (>=0.8.0)", "pytest-timeout (>=2.1.0)", "redis", "sphinx (>=6.0.0)", "types-redis"] [[package]] name = "pre-commit" @@ -2566,49 +2349,67 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" +[[package]] +name = "proto-plus" +version = "1.24.0" +description = "Beautiful, Pythonic protocol buffers." +optional = false +python-versions = ">=3.7" +files = [ + {file = "proto-plus-1.24.0.tar.gz", hash = "sha256:30b72a5ecafe4406b0d339db35b56c4059064e69227b8c3bda7462397f966445"}, + {file = "proto_plus-1.24.0-py3-none-any.whl", hash = "sha256:402576830425e5f6ce4c2a6702400ac79897dab0b4343821aa5188b0fab81a12"}, +] + +[package.dependencies] +protobuf = ">=3.19.0,<6.0.0dev" + +[package.extras] +testing = ["google-api-core (>=1.31.5)"] + [[package]] name = "protobuf" -version = "4.23.4" +version = "5.28.2" description = "" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "protobuf-4.23.4-cp310-abi3-win32.whl", hash = "sha256:5fea3c64d41ea5ecf5697b83e41d09b9589e6f20b677ab3c48e5f242d9b7897b"}, - {file = "protobuf-4.23.4-cp310-abi3-win_amd64.whl", hash = "sha256:7b19b6266d92ca6a2a87effa88ecc4af73ebc5cfde194dc737cf8ef23a9a3b12"}, - {file = "protobuf-4.23.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8547bf44fe8cec3c69e3042f5c4fb3e36eb2a7a013bb0a44c018fc1e427aafbd"}, - {file = "protobuf-4.23.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:fee88269a090ada09ca63551bf2f573eb2424035bcf2cb1b121895b01a46594a"}, - {file = "protobuf-4.23.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:effeac51ab79332d44fba74660d40ae79985901ac21bca408f8dc335a81aa597"}, - {file = "protobuf-4.23.4-cp37-cp37m-win32.whl", hash = "sha256:c3e0939433c40796ca4cfc0fac08af50b00eb66a40bbbc5dee711998fb0bbc1e"}, - {file = "protobuf-4.23.4-cp37-cp37m-win_amd64.whl", hash = "sha256:9053df6df8e5a76c84339ee4a9f5a2661ceee4a0dab019e8663c50ba324208b0"}, - {file = "protobuf-4.23.4-cp38-cp38-win32.whl", hash = "sha256:e1c915778d8ced71e26fcf43c0866d7499891bca14c4368448a82edc61fdbc70"}, - {file = "protobuf-4.23.4-cp38-cp38-win_amd64.whl", hash = "sha256:351cc90f7d10839c480aeb9b870a211e322bf05f6ab3f55fcb2f51331f80a7d2"}, - {file = "protobuf-4.23.4-cp39-cp39-win32.whl", hash = "sha256:6dd9b9940e3f17077e820b75851126615ee38643c2c5332aa7a359988820c720"}, - {file = "protobuf-4.23.4-cp39-cp39-win_amd64.whl", hash = "sha256:0a5759f5696895de8cc913f084e27fd4125e8fb0914bb729a17816a33819f474"}, - {file = "protobuf-4.23.4-py3-none-any.whl", hash = "sha256:e9d0be5bf34b275b9f87ba7407796556abeeba635455d036c7351f7c183ef8ff"}, - {file = "protobuf-4.23.4.tar.gz", hash = "sha256:ccd9430c0719dce806b93f89c91de7977304729e55377f872a92465d548329a9"}, + {file = "protobuf-5.28.2-cp310-abi3-win32.whl", hash = "sha256:eeea10f3dc0ac7e6b4933d32db20662902b4ab81bf28df12218aa389e9c2102d"}, + {file = "protobuf-5.28.2-cp310-abi3-win_amd64.whl", hash = "sha256:2c69461a7fcc8e24be697624c09a839976d82ae75062b11a0972e41fd2cd9132"}, + {file = "protobuf-5.28.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a8b9403fc70764b08d2f593ce44f1d2920c5077bf7d311fefec999f8c40f78b7"}, + {file = "protobuf-5.28.2-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:35cfcb15f213449af7ff6198d6eb5f739c37d7e4f1c09b5d0641babf2cc0c68f"}, + {file = "protobuf-5.28.2-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:5e8a95246d581eef20471b5d5ba010d55f66740942b95ba9b872d918c459452f"}, + {file = "protobuf-5.28.2-cp38-cp38-win32.whl", hash = "sha256:87317e9bcda04a32f2ee82089a204d3a2f0d3c8aeed16568c7daf4756e4f1fe0"}, + {file = "protobuf-5.28.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0ea0123dac3399a2eeb1a1443d82b7afc9ff40241433296769f7da42d142ec3"}, + {file = "protobuf-5.28.2-cp39-cp39-win32.whl", hash = "sha256:ca53faf29896c526863366a52a8f4d88e69cd04ec9571ed6082fa117fac3ab36"}, + {file = "protobuf-5.28.2-cp39-cp39-win_amd64.whl", hash = "sha256:8ddc60bf374785fb7cb12510b267f59067fa10087325b8e1855b898a0d81d276"}, + {file = "protobuf-5.28.2-py3-none-any.whl", hash = "sha256:52235802093bd8a2811abbe8bf0ab9c5f54cca0a751fdd3f6ac2a21438bffece"}, + {file = "protobuf-5.28.2.tar.gz", hash = "sha256:59379674ff119717404f7454647913787034f03fe7049cbef1d74a97bb4593f0"}, ] [[package]] name = "psutil" -version = "5.9.5" +version = "6.0.0" description = "Cross-platform lib for process and system monitoring in Python." optional = false -python-versions = ">=2.7, !=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-5.9.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f"}, - {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5"}, - {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4"}, - {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48"}, - {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4"}, - {file = "psutil-5.9.5-cp27-none-win32.whl", hash = "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f"}, - {file = "psutil-5.9.5-cp27-none-win_amd64.whl", hash = "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42"}, - {file = "psutil-5.9.5-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217"}, - {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da"}, - {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4"}, - {file = "psutil-5.9.5-cp36-abi3-win32.whl", hash = "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d"}, - {file = "psutil-5.9.5-cp36-abi3-win_amd64.whl", hash = "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9"}, - {file = "psutil-5.9.5-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30"}, - {file = "psutil-5.9.5.tar.gz", hash = "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c"}, + {file = "psutil-6.0.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a021da3e881cd935e64a3d0a20983bda0bb4cf80e4f74fa9bfcb1bc5785360c6"}, + {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1287c2b95f1c0a364d23bc6f2ea2365a8d4d9b726a3be7294296ff7ba97c17f0"}, + {file = "psutil-6.0.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a9a3dbfb4de4f18174528d87cc352d1f788b7496991cca33c6996f40c9e3c92c"}, + {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6ec7588fb3ddaec7344a825afe298db83fe01bfaaab39155fa84cf1c0d6b13c3"}, + {file = "psutil-6.0.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e7c870afcb7d91fdea2b37c24aeb08f98b6d67257a5cb0a8bc3ac68d0f1a68c"}, + {file = "psutil-6.0.0-cp27-none-win32.whl", hash = "sha256:02b69001f44cc73c1c5279d02b30a817e339ceb258ad75997325e0e6169d8b35"}, + {file = "psutil-6.0.0-cp27-none-win_amd64.whl", hash = "sha256:21f1fb635deccd510f69f485b87433460a603919b45e2a324ad65b0cc74f8fb1"}, + {file = "psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd"}, + {file = "psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132"}, + {file = "psutil-6.0.0-cp36-cp36m-win32.whl", hash = "sha256:fc8c9510cde0146432bbdb433322861ee8c3efbf8589865c8bf8d21cb30c4d14"}, + {file = "psutil-6.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:34859b8d8f423b86e4385ff3665d3f4d94be3cdf48221fbe476e883514fdb71c"}, + {file = "psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d"}, + {file = "psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3"}, + {file = "psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0"}, + {file = "psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2"}, ] [package.extras] @@ -2697,80 +2498,81 @@ files = [ [[package]] name = "pyasn1" -version = "0.4.8" -description = "ASN.1 types and codecs" +version = "0.5.1" +description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = false -python-versions = "*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, - {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, + {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, + {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, ] [[package]] name = "pyasn1-modules" -version = "0.3.0" +version = "0.4.1" description = "A collection of ASN.1-based protocols modules" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.8" files = [ - {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"}, - {file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"}, + {file = "pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd"}, + {file = "pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c"}, ] [package.dependencies] -pyasn1 = ">=0.4.6,<0.6.0" +pyasn1 = ">=0.4.6,<0.7.0" [[package]] name = "pycodestyle" -version = "2.12.0" +version = "2.12.1" description = "Python style guide checker" optional = false python-versions = ">=3.8" files = [ - {file = "pycodestyle-2.12.0-py2.py3-none-any.whl", hash = "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"}, - {file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"}, + {file = "pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3"}, + {file = "pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"}, ] [[package]] name = "pycparser" -version = "2.21" +version = "2.22" description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] [[package]] name = "pydantic" -version = "2.6.4" +version = "2.9.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.6.4-py3-none-any.whl", hash = "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5"}, - {file = "pydantic-2.6.4.tar.gz", hash = "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6"}, + {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, + {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, ] [package.dependencies] -annotated-types = ">=0.4.0" +annotated-types = ">=0.6.0" email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""} -pydantic-core = "2.16.3" -typing-extensions = ">=4.6.1" +pydantic-core = "2.23.4" +typing-extensions = {version = ">=4.6.1", markers = "python_version < \"3.13\""} [package.extras] email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] [[package]] name = "pydantic-collections" -version = "0.5.4" +version = "0.6.0" description = "Collections of pydantic models" optional = false python-versions = "*" files = [ - {file = "pydantic-collections-0.5.4.tar.gz", hash = "sha256:5bce65519456b4829f918c2456d58aac3620a866603461a702aafffe08845966"}, - {file = "pydantic_collections-0.5.4-py3-none-any.whl", hash = "sha256:5d107170c89fb17de229f5e8c4b4355af27594444fd0f93086048ccafa69238b"}, + {file = "pydantic_collections-0.6.0-py3-none-any.whl", hash = "sha256:ec559722abf6a0f80e6f00b3d28f0f39c0ed5feb1641166230eb75e9da880162"}, + {file = "pydantic_collections-0.6.0.tar.gz", hash = "sha256:c34d3fd1df5600b315cdecdd8e74eacd4c8c607b7e3f2c9392b2a15850a4ef9e"}, ] [package.dependencies] @@ -2779,90 +2581,100 @@ typing-extensions = ">=4.7.1" [[package]] name = "pydantic-core" -version = "2.16.3" -description = "" +version = "2.23.4" +description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, - {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, - {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, - {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, - {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, - {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, - {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, - {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, - {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, - {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, - {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, - {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, - {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, - {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, - {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, - {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, - {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, - {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, - {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, - {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, - {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, - {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, - {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, - {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, - {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, - {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, - {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, - {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, - {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, - {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"}, + {file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"}, + {file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"}, + {file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"}, + {file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"}, + {file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"}, + {file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"}, + {file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"}, + {file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb"}, + {file = "pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6"}, + {file = "pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605"}, + {file = "pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6"}, + {file = "pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e"}, + {file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, ] [package.dependencies] @@ -2890,27 +2702,27 @@ urllib3 = ">=1.26.0" [[package]] name = "pygments" -version = "2.16.1" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, - {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyjwt" -version = "2.8.0" +version = "2.9.0" description = "JSON Web Token implementation in Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, - {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, + {file = "PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850"}, + {file = "pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c"}, ] [package.dependencies] @@ -2918,8 +2730,8 @@ cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"cryp [package.extras] crypto = ["cryptography (>=3.4.0)"] -dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] -docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +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]] @@ -3068,13 +2880,13 @@ files = [ [[package]] name = "pysaml2" -version = "7.4.2" +version = "7.5.0" description = "Python implementation of SAML Version 2 Standard" optional = false python-versions = ">=3.9,<4.0" files = [ - {file = "pysaml2-7.4.2-py3-none-any.whl", hash = "sha256:6616abe0526915cabef6af3a81570bd4c339bedd8db3ab12dcd4fa0612896837"}, - {file = "pysaml2-7.4.2.tar.gz", hash = "sha256:2bc5147b3b2f902a9131bf08240c068becea29994aafb7654a63d7270ac5b63b"}, + {file = "pysaml2-7.5.0-py3-none-any.whl", hash = "sha256:bc6627cc344476a83c757f440a73fda1369f13b6fda1b4e16bca63ffbabb5318"}, + {file = "pysaml2-7.5.0.tar.gz", hash = "sha256:f36871d4e5ee857c6b85532e942550d2cf90ea4ee943d75eb681044bbc4f54f7"}, ] [package.dependencies] @@ -3084,7 +2896,7 @@ pyopenssl = "*" python-dateutil = "*" pytz = "*" requests = ">=2,<3" -xmlschema = ">=1.2.1" +xmlschema = ">=2,<3" [package.extras] s2repoze = ["paste", "repoze.who", "zope.interface"] @@ -3130,13 +2942,13 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale [[package]] name = "pytest-django" -version = "4.8.0" +version = "4.9.0" description = "A Django plugin for pytest." optional = false python-versions = ">=3.8" files = [ - {file = "pytest-django-4.8.0.tar.gz", hash = "sha256:5d054fe011c56f3b10f978f41a8efb2e5adfc7e680ef36fb571ada1f24779d90"}, - {file = "pytest_django-4.8.0-py3-none-any.whl", hash = "sha256:ca1ddd1e0e4c227cf9e3e40a6afc6d106b3e70868fd2ac5798a22501271cd0c7"}, + {file = "pytest_django-4.9.0-py3-none-any.whl", hash = "sha256:1d83692cb39188682dbb419ff0393867e9904094a549a7d38a3154d5731b2b99"}, + {file = "pytest_django-4.9.0.tar.gz", hash = "sha256:8bf7bc358c9ae6f6fc51b6cebb190fe20212196e6807121f11bd6a3b03428314"}, ] [package.dependencies] @@ -3214,13 +3026,13 @@ testing = ["filelock"] [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {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] @@ -3242,13 +3054,13 @@ cli = ["click (>=5.0)"] [[package]] name = "python-gnupg" -version = "0.5.1" +version = "0.5.3" description = "A wrapper for the Gnu Privacy Guard (GPG or GnuPG)" optional = false python-versions = "*" files = [ - {file = "python-gnupg-0.5.1.tar.gz", hash = "sha256:5674bad4e93876c0b0d3197e314d7f942d39018bf31e2b833f6788a6813c3fb8"}, - {file = "python_gnupg-0.5.1-py2.py3-none-any.whl", hash = "sha256:bf9b2d9032ef38139b7d64184176cd0b293eaeae6e4f93f50e304c7051174482"}, + {file = "python-gnupg-0.5.3.tar.gz", hash = "sha256:290d8ddb9cd63df96cfe9284b9b265f19fd6e145e5582dc58fd7271f026d0a47"}, + {file = "python_gnupg-0.5.3-py2.py3-none-any.whl", hash = "sha256:2f8a4c6f63766feca6cc1416408f8b84e1b914fe7b54514e570fc5cbe92e9248"}, ] [[package]] @@ -3262,6 +3074,20 @@ files = [ {file = "python_http_client-3.3.7.tar.gz", hash = "sha256:bf841ee45262747e00dec7ee9971dfb8c7d83083f5713596488d67739170cea0"}, ] +[[package]] +name = "python-ipware" +version = "3.0.0" +description = "A Python package to retrieve user's IP address" +optional = false +python-versions = ">=3.7" +files = [ + {file = "python_ipware-3.0.0-py3-none-any.whl", hash = "sha256:fc936e6e7ec9fcc107f9315df40658f468ac72f739482a707181742882e36b60"}, + {file = "python_ipware-3.0.0.tar.gz", hash = "sha256:9117b1c4dddcb5d5ca49e6a9617de2fc66aec2ef35394563ac4eecabdf58c062"}, +] + +[package.extras] +dev = ["coverage[toml]", "coveralls (>=3.3,<4.0)", "ruff", "twine"] + [[package]] name = "python3-openid" version = "3.2.0" @@ -3282,114 +3108,121 @@ postgresql = ["psycopg2"] [[package]] name = "pytz" -version = "2023.4" +version = "2024.2" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2023.4-py2.py3-none-any.whl", hash = "sha256:f90ef520d95e7c46951105338d918664ebfd6f1d995bd7d153127ce90efafa6a"}, - {file = "pytz-2023.4.tar.gz", hash = "sha256:31d4583c4ed539cd037956140d695e42c033a19e984bfce9964a3f7d59bc2b40"}, + {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, + {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, ] [[package]] name = "pywin32" -version = "306" +version = "307" description = "Python for Window Extensions" optional = false python-versions = "*" files = [ - {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, - {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, - {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, - {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, - {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, - {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, - {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, - {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, - {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, - {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, - {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, - {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, - {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, - {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, + {file = "pywin32-307-cp310-cp310-win32.whl", hash = "sha256:f8f25d893c1e1ce2d685ef6d0a481e87c6f510d0f3f117932781f412e0eba31b"}, + {file = "pywin32-307-cp310-cp310-win_amd64.whl", hash = "sha256:36e650c5e5e6b29b5d317385b02d20803ddbac5d1031e1f88d20d76676dd103d"}, + {file = "pywin32-307-cp310-cp310-win_arm64.whl", hash = "sha256:0c12d61e0274e0c62acee79e3e503c312426ddd0e8d4899c626cddc1cafe0ff4"}, + {file = "pywin32-307-cp311-cp311-win32.whl", hash = "sha256:fec5d27cc893178fab299de911b8e4d12c5954e1baf83e8a664311e56a272b75"}, + {file = "pywin32-307-cp311-cp311-win_amd64.whl", hash = "sha256:987a86971753ed7fdd52a7fb5747aba955b2c7fbbc3d8b76ec850358c1cc28c3"}, + {file = "pywin32-307-cp311-cp311-win_arm64.whl", hash = "sha256:fd436897c186a2e693cd0437386ed79f989f4d13d6f353f8787ecbb0ae719398"}, + {file = "pywin32-307-cp312-cp312-win32.whl", hash = "sha256:07649ec6b01712f36debf39fc94f3d696a46579e852f60157a729ac039df0815"}, + {file = "pywin32-307-cp312-cp312-win_amd64.whl", hash = "sha256:00d047992bb5dcf79f8b9b7c81f72e0130f9fe4b22df613f755ab1cc021d8347"}, + {file = "pywin32-307-cp312-cp312-win_arm64.whl", hash = "sha256:b53658acbfc6a8241d72cc09e9d1d666be4e6c99376bc59e26cdb6223c4554d2"}, + {file = "pywin32-307-cp313-cp313-win32.whl", hash = "sha256:ea4d56e48dc1ab2aa0a5e3c0741ad6e926529510516db7a3b6981a1ae74405e5"}, + {file = "pywin32-307-cp313-cp313-win_amd64.whl", hash = "sha256:576d09813eaf4c8168d0bfd66fb7cb3b15a61041cf41598c2db4a4583bf832d2"}, + {file = "pywin32-307-cp313-cp313-win_arm64.whl", hash = "sha256:b30c9bdbffda6a260beb2919f918daced23d32c79109412c2085cbc513338a0a"}, + {file = "pywin32-307-cp37-cp37m-win32.whl", hash = "sha256:5101472f5180c647d4525a0ed289ec723a26231550dbfd369ec19d5faf60e511"}, + {file = "pywin32-307-cp37-cp37m-win_amd64.whl", hash = "sha256:05de55a7c110478dc4b202230e98af5e0720855360d2b31a44bb4e296d795fba"}, + {file = "pywin32-307-cp38-cp38-win32.whl", hash = "sha256:13d059fb7f10792542082f5731d5d3d9645320fc38814759313e5ee97c3fac01"}, + {file = "pywin32-307-cp38-cp38-win_amd64.whl", hash = "sha256:7e0b2f93769d450a98ac7a31a087e07b126b6d571e8b4386a5762eb85325270b"}, + {file = "pywin32-307-cp39-cp39-win32.whl", hash = "sha256:55ee87f2f8c294e72ad9d4261ca423022310a6e79fb314a8ca76ab3f493854c6"}, + {file = "pywin32-307-cp39-cp39-win_amd64.whl", hash = "sha256:e9d5202922e74985b037c9ef46778335c102b74b95cec70f629453dbe7235d87"}, ] [[package]] name = "pyyaml" -version = "6.0.1" +version = "6.0.2" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] name = "redis" -version = "5.0.1" +version = "5.1.1" description = "Python client for Redis database and key-value store" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"}, - {file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"}, + {file = "redis-5.1.1-py3-none-any.whl", hash = "sha256:f8ea06b7482a668c6475ae202ed8d9bcaa409f6e87fb77ed1043d912afd62e24"}, + {file = "redis-5.1.1.tar.gz", hash = "sha256:f6c997521fedbae53387307c5d0bf784d9acc28d9f1d058abeac566ec4dbed72"}, ] [package.dependencies] -async-timeout = {version = ">=4.0.2", markers = "python_full_version <= \"3.11.2\""} +async-timeout = {version = ">=4.0.3", markers = "python_full_version < \"3.11.3\""} [package.extras] -hiredis = ["hiredis (>=1.0.0)"] -ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] +hiredis = ["hiredis (>=3.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==23.2.1)", "requests (>=2.31.0)"] [[package]] name = "requests" @@ -3431,32 +3264,30 @@ dev = ["black (>=22.3.0)", "build (>=0.7.0)", "isort (>=5.11.4)", "pyflakes (>=2 [[package]] name = "requests-mock" -version = "1.11.0" +version = "1.12.1" description = "Mock out responses from the requests package" optional = false -python-versions = "*" +python-versions = ">=3.5" files = [ - {file = "requests-mock-1.11.0.tar.gz", hash = "sha256:ef10b572b489a5f28e09b708697208c4a3b2b89ef80a9f01584340ea357ec3c4"}, - {file = "requests_mock-1.11.0-py2.py3-none-any.whl", hash = "sha256:f7fae383f228633f6bececebdab236c478ace2284d6292c6e7e2867b9ab74d15"}, + {file = "requests-mock-1.12.1.tar.gz", hash = "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401"}, + {file = "requests_mock-1.12.1-py2.py3-none-any.whl", hash = "sha256:b1e37054004cdd5e56c84454cc7df12b25f90f382159087f4b6915aaeef39563"}, ] [package.dependencies] -requests = ">=2.3,<3" -six = "*" +requests = ">=2.22,<3" [package.extras] fixture = ["fixtures"] -test = ["fixtures", "mock", "purl", "pytest", "requests-futures", "sphinx", "testtools"] [[package]] name = "requests-oauthlib" -version = "1.3.1" +version = "2.0.0" description = "OAuthlib authentication support for Requests." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.4" files = [ - {file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"}, - {file = "requests_oauthlib-1.3.1-py2.py3-none-any.whl", hash = "sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5"}, + {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] @@ -3660,122 +3491,152 @@ tornado = ["tornado (>=6)"] [[package]] name = "setuptools" -version = "70.0.0" +version = "75.1.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-70.0.0-py3-none-any.whl", hash = "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4"}, - {file = "setuptools-70.0.0.tar.gz", hash = "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0"}, + {file = "setuptools-75.1.0-py3-none-any.whl", hash = "sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2"}, + {file = "setuptools-75.1.0.tar.gz", hash = "sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] [[package]] name = "shortuuid" -version = "1.0.11" +version = "1.0.13" description = "A generator library for concise, unambiguous and URL-safe UUIDs." optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "shortuuid-1.0.11-py3-none-any.whl", hash = "sha256:27ea8f28b1bd0bf8f15057a3ece57275d2059d2b0bb02854f02189962c13b6aa"}, - {file = "shortuuid-1.0.11.tar.gz", hash = "sha256:fc75f2615914815a8e4cb1501b3a513745cb66ef0fd5fc6fb9f8c3fa3481f789"}, + {file = "shortuuid-1.0.13-py3-none-any.whl", hash = "sha256:a482a497300b49b4953e15108a7913244e1bb0d41f9d332f5e9925dba33a3c5a"}, + {file = "shortuuid-1.0.13.tar.gz", hash = "sha256:3bb9cf07f606260584b1df46399c0b87dd84773e7b25912b7e391e30797c5e72"}, ] [[package]] name = "simplejson" -version = "3.19.1" +version = "3.19.3" description = "Simple, fast, extensible JSON encoder/decoder for Python" optional = false -python-versions = ">=2.5, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "simplejson-3.19.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:412e58997a30c5deb8cab5858b8e2e5b40ca007079f7010ee74565cc13d19665"}, - {file = "simplejson-3.19.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e765b1f47293dedf77946f0427e03ee45def2862edacd8868c6cf9ab97c8afbd"}, - {file = "simplejson-3.19.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:3231100edee292da78948fa0a77dee4e5a94a0a60bcba9ed7a9dc77f4d4bb11e"}, - {file = "simplejson-3.19.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:081ea6305b3b5e84ae7417e7f45956db5ea3872ec497a584ec86c3260cda049e"}, - {file = "simplejson-3.19.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:f253edf694ce836631b350d758d00a8c4011243d58318fbfbe0dd54a6a839ab4"}, - {file = "simplejson-3.19.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:5db86bb82034e055257c8e45228ca3dbce85e38d7bfa84fa7b2838e032a3219c"}, - {file = "simplejson-3.19.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:69a8b10a4f81548bc1e06ded0c4a6c9042c0be0d947c53c1ed89703f7e613950"}, - {file = "simplejson-3.19.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:58ee5e24d6863b22194020eb62673cf8cc69945fcad6b283919490f6e359f7c5"}, - {file = "simplejson-3.19.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:73d0904c2471f317386d4ae5c665b16b5c50ab4f3ee7fd3d3b7651e564ad74b1"}, - {file = "simplejson-3.19.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:66d780047c31ff316ee305c3f7550f352d87257c756413632303fc59fef19eac"}, - {file = "simplejson-3.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cd4d50a27b065447c9c399f0bf0a993bd0e6308db8bbbfbc3ea03b41c145775a"}, - {file = "simplejson-3.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c16ec6a67a5f66ab004190829eeede01c633936375edcad7cbf06d3241e5865"}, - {file = "simplejson-3.19.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17a963e8dd4d81061cc05b627677c1f6a12e81345111fbdc5708c9f088d752c9"}, - {file = "simplejson-3.19.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e78d79b10aa92f40f54178ada2b635c960d24fc6141856b926d82f67e56d169"}, - {file = "simplejson-3.19.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad071cd84a636195f35fa71de2186d717db775f94f985232775794d09f8d9061"}, - {file = "simplejson-3.19.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e7c70f19405e5f99168077b785fe15fcb5f9b3c0b70b0b5c2757ce294922c8c"}, - {file = "simplejson-3.19.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:54fca2b26bcd1c403146fd9461d1da76199442297160721b1d63def2a1b17799"}, - {file = "simplejson-3.19.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:48600a6e0032bed17c20319d91775f1797d39953ccfd68c27f83c8d7fc3b32cb"}, - {file = "simplejson-3.19.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:93f5ac30607157a0b2579af59a065bcfaa7fadeb4875bf927a8f8b6739c8d910"}, - {file = "simplejson-3.19.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b79642a599740603ca86cf9df54f57a2013c47e1dd4dd2ae4769af0a6816900"}, - {file = "simplejson-3.19.1-cp310-cp310-win32.whl", hash = "sha256:d9f2c27f18a0b94107d57294aab3d06d6046ea843ed4a45cae8bd45756749f3a"}, - {file = "simplejson-3.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:5673d27806085d2a413b3be5f85fad6fca4b7ffd31cfe510bbe65eea52fff571"}, - {file = "simplejson-3.19.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:79c748aa61fd8098d0472e776743de20fae2686edb80a24f0f6593a77f74fe86"}, - {file = "simplejson-3.19.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:390f4a8ca61d90bcf806c3ad644e05fa5890f5b9a72abdd4ca8430cdc1e386fa"}, - {file = "simplejson-3.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d61482b5d18181e6bb4810b4a6a24c63a490c3a20e9fbd7876639653e2b30a1a"}, - {file = "simplejson-3.19.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2541fdb7467ef9bfad1f55b6c52e8ea52b3ce4a0027d37aff094190a955daa9d"}, - {file = "simplejson-3.19.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46133bc7dd45c9953e6ee4852e3de3d5a9a4a03b068bd238935a5c72f0a1ce34"}, - {file = "simplejson-3.19.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f96def94576f857abf58e031ce881b5a3fc25cbec64b2bc4824824a8a4367af9"}, - {file = "simplejson-3.19.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f14ecca970d825df0d29d5c6736ff27999ee7bdf5510e807f7ad8845f7760ce"}, - {file = "simplejson-3.19.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:66389b6b6ee46a94a493a933a26008a1bae0cfadeca176933e7ff6556c0ce998"}, - {file = "simplejson-3.19.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:22b867205cd258050c2625325fdd9a65f917a5aff22a23387e245ecae4098e78"}, - {file = "simplejson-3.19.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c39fa911e4302eb79c804b221ddec775c3da08833c0a9120041dd322789824de"}, - {file = "simplejson-3.19.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:65dafe413b15e8895ad42e49210b74a955c9ae65564952b0243a18fb35b986cc"}, - {file = "simplejson-3.19.1-cp311-cp311-win32.whl", hash = "sha256:f05d05d99fce5537d8f7a0af6417a9afa9af3a6c4bb1ba7359c53b6257625fcb"}, - {file = "simplejson-3.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:b46aaf0332a8a9c965310058cf3487d705bf672641d2c43a835625b326689cf4"}, - {file = "simplejson-3.19.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b438e5eaa474365f4faaeeef1ec3e8d5b4e7030706e3e3d6b5bee6049732e0e6"}, - {file = "simplejson-3.19.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa9d614a612ad02492f704fbac636f666fa89295a5d22b4facf2d665fc3b5ea9"}, - {file = "simplejson-3.19.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46e89f58e4bed107626edce1cf098da3664a336d01fc78fddcfb1f397f553d44"}, - {file = "simplejson-3.19.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96ade243fb6f3b57e7bd3b71e90c190cd0f93ec5dce6bf38734a73a2e5fa274f"}, - {file = "simplejson-3.19.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed18728b90758d171f0c66c475c24a443ede815cf3f1a91e907b0db0ebc6e508"}, - {file = "simplejson-3.19.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:6a561320485017ddfc21bd2ed5de2d70184f754f1c9b1947c55f8e2b0163a268"}, - {file = "simplejson-3.19.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:2098811cd241429c08b7fc5c9e41fcc3f59f27c2e8d1da2ccdcf6c8e340ab507"}, - {file = "simplejson-3.19.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:8f8d179393e6f0cf6c7c950576892ea6acbcea0a320838c61968ac7046f59228"}, - {file = "simplejson-3.19.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:eff87c68058374e45225089e4538c26329a13499bc0104b52b77f8428eed36b2"}, - {file = "simplejson-3.19.1-cp36-cp36m-win32.whl", hash = "sha256:d300773b93eed82f6da138fd1d081dc96fbe53d96000a85e41460fe07c8d8b33"}, - {file = "simplejson-3.19.1-cp36-cp36m-win_amd64.whl", hash = "sha256:37724c634f93e5caaca04458f267836eb9505d897ab3947b52f33b191bf344f3"}, - {file = "simplejson-3.19.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:74bf802debe68627227ddb665c067eb8c73aa68b2476369237adf55c1161b728"}, - {file = "simplejson-3.19.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70128fb92932524c89f373e17221cf9535d7d0c63794955cc3cd5868e19f5d38"}, - {file = "simplejson-3.19.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8090e75653ea7db75bc21fa5f7bcf5f7bdf64ea258cbbac45c7065f6324f1b50"}, - {file = "simplejson-3.19.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a755f7bfc8adcb94887710dc70cc12a69a454120c6adcc6f251c3f7b46ee6aac"}, - {file = "simplejson-3.19.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ccb2c1877bc9b25bc4f4687169caa925ffda605d7569c40e8e95186e9a5e58b"}, - {file = "simplejson-3.19.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:919bc5aa4d8094cf8f1371ea9119e5d952f741dc4162810ab714aec948a23fe5"}, - {file = "simplejson-3.19.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e333c5b62e93949f5ac27e6758ba53ef6ee4f93e36cc977fe2e3df85c02f6dc4"}, - {file = "simplejson-3.19.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3a4480e348000d89cf501b5606415f4d328484bbb431146c2971123d49fd8430"}, - {file = "simplejson-3.19.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cb502cde018e93e75dc8fc7bb2d93477ce4f3ac10369f48866c61b5e031db1fd"}, - {file = "simplejson-3.19.1-cp37-cp37m-win32.whl", hash = "sha256:f41915a4e1f059dfad614b187bc06021fefb5fc5255bfe63abf8247d2f7a646a"}, - {file = "simplejson-3.19.1-cp37-cp37m-win_amd64.whl", hash = "sha256:3844305bc33d52c4975da07f75b480e17af3558c0d13085eaa6cc2f32882ccf7"}, - {file = "simplejson-3.19.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1cb19eacb77adc5a9720244d8d0b5507421d117c7ed4f2f9461424a1829e0ceb"}, - {file = "simplejson-3.19.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:926957b278de22797bfc2f004b15297013843b595b3cd7ecd9e37ccb5fad0b72"}, - {file = "simplejson-3.19.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b0e9a5e66969f7a47dc500e3dba8edc3b45d4eb31efb855c8647700a3493dd8a"}, - {file = "simplejson-3.19.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79d46e7e33c3a4ef853a1307b2032cfb7220e1a079d0c65488fbd7118f44935a"}, - {file = "simplejson-3.19.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:344a5093b71c1b370968d0fbd14d55c9413cb6f0355fdefeb4a322d602d21776"}, - {file = "simplejson-3.19.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23fbb7b46d44ed7cbcda689295862851105c7594ae5875dce2a70eeaa498ff86"}, - {file = "simplejson-3.19.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d3025e7e9ddb48813aec2974e1a7e68e63eac911dd5e0a9568775de107ac79a"}, - {file = "simplejson-3.19.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:87b190e6ceec286219bd6b6f13547ca433f977d4600b4e81739e9ac23b5b9ba9"}, - {file = "simplejson-3.19.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:dc935d8322ba9bc7b84f99f40f111809b0473df167bf5b93b89fb719d2c4892b"}, - {file = "simplejson-3.19.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3b652579c21af73879d99c8072c31476788c8c26b5565687fd9db154070d852a"}, - {file = "simplejson-3.19.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6aa7ca03f25b23b01629b1c7f78e1cd826a66bfb8809f8977a3635be2ec48f1a"}, - {file = "simplejson-3.19.1-cp38-cp38-win32.whl", hash = "sha256:08be5a241fdf67a8e05ac7edbd49b07b638ebe4846b560673e196b2a25c94b92"}, - {file = "simplejson-3.19.1-cp38-cp38-win_amd64.whl", hash = "sha256:ca56a6c8c8236d6fe19abb67ef08d76f3c3f46712c49a3b6a5352b6e43e8855f"}, - {file = "simplejson-3.19.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6424d8229ba62e5dbbc377908cfee9b2edf25abd63b855c21f12ac596cd18e41"}, - {file = "simplejson-3.19.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:547ea86ca408a6735335c881a2e6208851027f5bfd678d8f2c92a0f02c7e7330"}, - {file = "simplejson-3.19.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:889328873c35cb0b2b4c83cbb83ec52efee5a05e75002e2c0c46c4e42790e83c"}, - {file = "simplejson-3.19.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44cdb4e544134f305b033ad79ae5c6b9a32e7c58b46d9f55a64e2a883fbbba01"}, - {file = "simplejson-3.19.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc2b3f06430cbd4fac0dae5b2974d2bf14f71b415fb6de017f498950da8159b1"}, - {file = "simplejson-3.19.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d125e754d26c0298715bdc3f8a03a0658ecbe72330be247f4b328d229d8cf67f"}, - {file = "simplejson-3.19.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:476c8033abed7b1fd8db62a7600bf18501ce701c1a71179e4ce04ac92c1c5c3c"}, - {file = "simplejson-3.19.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:199a0bcd792811c252d71e3eabb3d4a132b3e85e43ebd93bfd053d5b59a7e78b"}, - {file = "simplejson-3.19.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a79b439a6a77649bb8e2f2644e6c9cc0adb720fc55bed63546edea86e1d5c6c8"}, - {file = "simplejson-3.19.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:203412745fed916fc04566ecef3f2b6c872b52f1e7fb3a6a84451b800fb508c1"}, - {file = "simplejson-3.19.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ca922c61d87b4c38f37aa706520328ffe22d7ac1553ef1cadc73f053a673553"}, - {file = "simplejson-3.19.1-cp39-cp39-win32.whl", hash = "sha256:3e0902c278243d6f7223ba3e6c5738614c971fd9a887fff8feaa8dcf7249c8d4"}, - {file = "simplejson-3.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:d396b610e77b0c438846607cd56418bfc194973b9886550a98fd6724e8c6cfec"}, - {file = "simplejson-3.19.1-py3-none-any.whl", hash = "sha256:4710806eb75e87919b858af0cba4ffedc01b463edc3982ded7b55143f39e41e1"}, - {file = "simplejson-3.19.1.tar.gz", hash = "sha256:6277f60848a7d8319d27d2be767a7546bc965535b28070e310b3a9af90604a4c"}, +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.5" +files = [ + {file = "simplejson-3.19.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f39caec26007a2d0efab6b8b1d74873ede9351962707afab622cc2285dd26ed0"}, + {file = "simplejson-3.19.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:83c87706265ae3028e8460d08b05f30254c569772e859e5ba61fe8af2c883468"}, + {file = "simplejson-3.19.3-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:0b5ddd2c7d1d3f4d23224bc8a04bbf1430ae9a8149c05b90f8fc610f7f857a23"}, + {file = "simplejson-3.19.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:ad0e0b1ce9bd3edb5cf64b5b5b76eacbfdac8c5367153aeeec8a8b1407f68342"}, + {file = "simplejson-3.19.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:93be280fc69a952c76e261036312c20b910e7fa9e234f1d89bdfe3fa34f8a023"}, + {file = "simplejson-3.19.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:6d43e24b88c80f997081503f693be832fc90854f278df277dd54f8a4c847ab61"}, + {file = "simplejson-3.19.3-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2876027ebdd599d730d36464debe84619b0368e9a642ca6e7c601be55aed439e"}, + {file = "simplejson-3.19.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:0766ca6222b410e08e0053a0dda3606cafb3973d5d00538307f631bb59743396"}, + {file = "simplejson-3.19.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:50d8b742d74c449c4dcac570d08ce0f21f6a149d2d9cf7652dbf2ba9a1bc729a"}, + {file = "simplejson-3.19.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd011fc3c1d88b779645495fdb8189fb318a26981eebcce14109460e062f209b"}, + {file = "simplejson-3.19.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:637c4d4b81825c1f4d651e56210bd35b5604034b192b02d2d8f17f7ce8c18f42"}, + {file = "simplejson-3.19.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f56eb03bc9e432bb81adc8ecff2486d39feb371abb442964ffb44f6db23b332"}, + {file = "simplejson-3.19.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ef59a53be400c1fad2c914b8d74c9d42384fed5174f9321dd021b7017fd40270"}, + {file = "simplejson-3.19.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72e8abbc86fcac83629a030888b45fed3a404d54161118be52cb491cd6975d3e"}, + {file = "simplejson-3.19.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8efb03ca77bd7725dfacc9254df00d73e6f43013cf39bd37ef1a8ed0ebb5165"}, + {file = "simplejson-3.19.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:add8850db04b98507a8b62d248a326ecc8561e6d24336d1ca5c605bbfaab4cad"}, + {file = "simplejson-3.19.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fc3dc9fb413fc34c396f52f4c87de18d0bd5023804afa8ab5cc224deeb6a9900"}, + {file = "simplejson-3.19.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4dfa420bb9225dd33b6efdabde7c6a671b51150b9b1d9c4e5cd74d3b420b3fe1"}, + {file = "simplejson-3.19.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7b5c472099b39b274dcde27f1113db8d818c9aa3ba8f78cbb8ad04a4c1ac2118"}, + {file = "simplejson-3.19.3-cp310-cp310-win32.whl", hash = "sha256:817abad79241ed4a507b3caf4d3f2be5079f39d35d4c550a061988986bffd2ec"}, + {file = "simplejson-3.19.3-cp310-cp310-win_amd64.whl", hash = "sha256:dd5b9b1783e14803e362a558680d88939e830db2466f3fa22df5c9319f8eea94"}, + {file = "simplejson-3.19.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e88abff510dcff903a18d11c2a75f9964e768d99c8d147839913886144b2065e"}, + {file = "simplejson-3.19.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:934a50a614fb831614db5dbfba35127ee277624dda4d15895c957d2f5d48610c"}, + {file = "simplejson-3.19.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:212fce86a22188b0c7f53533b0f693ea9605c1a0f02c84c475a30616f55a744d"}, + {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d9e8f836688a8fabe6a6b41b334aa550a6823f7b4ac3d3712fc0ad8655be9a8"}, + {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23228037dc5d41c36666384062904d74409a62f52283d9858fa12f4c22cffad1"}, + {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0791f64fed7d4abad639491f8a6b1ba56d3c604eb94b50f8697359b92d983f36"}, + {file = "simplejson-3.19.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4f614581b61a26fbbba232a1391f6cee82bc26f2abbb6a0b44a9bba25c56a1c"}, + {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1df0aaf1cb787fdf34484ed4a1f0c545efd8811f6028623290fef1a53694e597"}, + {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:951095be8d4451a7182403354c22ec2de3e513e0cc40408b689af08d02611588"}, + {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:2a954b30810988feeabde843e3263bf187697e0eb5037396276db3612434049b"}, + {file = "simplejson-3.19.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c40df31a75de98db2cdfead6074d4449cd009e79f54c1ebe5e5f1f153c68ad20"}, + {file = "simplejson-3.19.3-cp311-cp311-win32.whl", hash = "sha256:7e2a098c21ad8924076a12b6c178965d88a0ad75d1de67e1afa0a66878f277a5"}, + {file = "simplejson-3.19.3-cp311-cp311-win_amd64.whl", hash = "sha256:c9bedebdc5fdad48af8783022bae307746d54006b783007d1d3c38e10872a2c6"}, + {file = "simplejson-3.19.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:66a0399e21c2112acacfebf3d832ebe2884f823b1c7e6d1363f2944f1db31a99"}, + {file = "simplejson-3.19.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6ef9383c5e05f445be60f1735c1816163c874c0b1ede8bb4390aff2ced34f333"}, + {file = "simplejson-3.19.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:42e5acf80d4d971238d4df97811286a044d720693092b20a56d5e56b7dcc5d09"}, + {file = "simplejson-3.19.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0b0efc7279d768db7c74d3d07f0b5c81280d16ae3fb14e9081dc903e8360771"}, + {file = "simplejson-3.19.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0552eb06e7234da892e1d02365cd2b7b2b1f8233aa5aabdb2981587b7cc92ea0"}, + {file = "simplejson-3.19.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf6a3b9a7d7191471b464fe38f684df10eb491ec9ea454003edb45a011ab187"}, + {file = "simplejson-3.19.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7017329ca8d4dca94ad5e59f496e5fc77630aecfc39df381ffc1d37fb6b25832"}, + {file = "simplejson-3.19.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:67a20641afebf4cfbcff50061f07daad1eace6e7b31d7622b6fa2c40d43900ba"}, + {file = "simplejson-3.19.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:dd6a7dabcc4c32daf601bc45e01b79175dde4b52548becea4f9545b0a4428169"}, + {file = "simplejson-3.19.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:08f9b443a94e72dd02c87098c96886d35790e79e46b24e67accafbf13b73d43b"}, + {file = "simplejson-3.19.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa97278ae6614346b5ca41a45a911f37a3261b57dbe4a00602048652c862c28b"}, + {file = "simplejson-3.19.3-cp312-cp312-win32.whl", hash = "sha256:ef28c3b328d29b5e2756903aed888960bc5df39b4c2eab157ae212f70ed5bf74"}, + {file = "simplejson-3.19.3-cp312-cp312-win_amd64.whl", hash = "sha256:1e662336db50ad665777e6548b5076329a94a0c3d4a0472971c588b3ef27de3a"}, + {file = "simplejson-3.19.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0959e6cb62e3994b5a40e31047ff97ef5c4138875fae31659bead691bed55896"}, + {file = "simplejson-3.19.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a7bfad839c624e139a4863007233a3f194e7c51551081f9789cba52e4da5167"}, + {file = "simplejson-3.19.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afab2f7f2486a866ff04d6d905e9386ca6a231379181a3838abce1f32fbdcc37"}, + {file = "simplejson-3.19.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d00313681015ac498e1736b304446ee6d1c72c5b287cd196996dad84369998f7"}, + {file = "simplejson-3.19.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d936ae682d5b878af9d9eb4d8bb1fdd5e41275c8eb59ceddb0aeed857bb264a2"}, + {file = "simplejson-3.19.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c6657485393f2e9b8177c77a7634f13ebe70d5e6de150aae1677d91516ce6b"}, + {file = "simplejson-3.19.3-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a6a750d3c7461b1c47cfc6bba8d9e57a455e7c5f80057d2a82f738040dd1129"}, + {file = "simplejson-3.19.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ea7a4a998c87c5674a27089e022110a1a08a7753f21af3baf09efe9915c23c3c"}, + {file = "simplejson-3.19.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6300680d83a399be2b8f3b0ef7ef90b35d2a29fe6e9c21438097e0938bbc1564"}, + {file = "simplejson-3.19.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ab69f811a660c362651ae395eba8ce84f84c944cea0df5718ea0ba9d1e4e7252"}, + {file = "simplejson-3.19.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:256e09d0f94d9c3d177d9e95fd27a68c875a4baa2046633df387b86b652f5747"}, + {file = "simplejson-3.19.3-cp313-cp313-win32.whl", hash = "sha256:2c78293470313aefa9cfc5e3f75ca0635721fb016fb1121c1c5b0cb8cc74712a"}, + {file = "simplejson-3.19.3-cp313-cp313-win_amd64.whl", hash = "sha256:3bbcdc438dc1683b35f7a8dc100960c721f922f9ede8127f63bed7dfded4c64c"}, + {file = "simplejson-3.19.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:89b35433186e977fa86ff1fd179c1fadff39cfa3afa1648dab0b6ca53153acd9"}, + {file = "simplejson-3.19.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d43c2d7504eda566c50203cdc9dc043aff6f55f1b7dae0dcd79dfefef9159d1c"}, + {file = "simplejson-3.19.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6890ff9cf0bd2e1d487e2a8869ebd620a44684c0a9667fa5ee751d099d5d84c8"}, + {file = "simplejson-3.19.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1069143a8fb3905e1bc0696c62be7e3adf812e9f1976ac9ae15b05112ff57cc9"}, + {file = "simplejson-3.19.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb324bb903330cbb35d87cce367a12631cd5720afa06e5b9c906483970946da6"}, + {file = "simplejson-3.19.3-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:0a32859d45d7b85fb803bb68f6bee14526991a1190269116c33399fa0daf9bbf"}, + {file = "simplejson-3.19.3-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:23833ee7e791ec968b744dfee2a2d39df7152050051096caf4296506d75608d8"}, + {file = "simplejson-3.19.3-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:d73efb03c5b39249c82488a994f0998f9e4399e3d085209d2120503305ba77a8"}, + {file = "simplejson-3.19.3-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:7923878b7a0142d39763ec2dbecff3053c1bedd3653585a8474666e420fe83f5"}, + {file = "simplejson-3.19.3-cp36-cp36m-win32.whl", hash = "sha256:7355c7203353c36d46c4e7b6055293b3d2be097bbc5e2874a2b8a7259f0325dd"}, + {file = "simplejson-3.19.3-cp36-cp36m-win_amd64.whl", hash = "sha256:d1b8b4d6379fe55f471914345fe6171d81a18649dacf3248abfc9c349b4442eb"}, + {file = "simplejson-3.19.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d36608557b4dcd7a62c29ad4cd7c5a1720bbf7dc942eff9dc42d2c542a5f042d"}, + {file = "simplejson-3.19.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7137e69c6781ecf23afab064be94a277236c9cba31aa48ff1a0ec3995c69171e"}, + {file = "simplejson-3.19.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76f8c28fe2d426182405b18ddf3001fce47835a557dc15c3d8bdea01c03361da"}, + {file = "simplejson-3.19.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff7bc1bbdaa3e487c9469128bf39408e91f5573901cb852e03af378d3582c52d"}, + {file = "simplejson-3.19.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0782cb9bf827f0c488b6aa0f2819f618308a3caf2973cfd792e45d631bec4db"}, + {file = "simplejson-3.19.3-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:6fea0716c593dabb4392c4996d4e902a83b2428e6da82938cf28a523a11eb277"}, + {file = "simplejson-3.19.3-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:8f41bb5370b34f63171e65fdb00e12be1d83675cecb23e627df26f4c88dfc021"}, + {file = "simplejson-3.19.3-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:37105d1d708365b91165e1a6e505bdecc88637091348cf4b6adcdcb4f5a5fb8b"}, + {file = "simplejson-3.19.3-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:b9198c1f1f8910a3b86b60f4fe2556d9d28d3fefe35bffe6be509a27402e694d"}, + {file = "simplejson-3.19.3-cp37-cp37m-win32.whl", hash = "sha256:bc164f32dd9691e7082ce5df24b4cf8c6c394bbf9bdeeb5d843127cd07ab8ad2"}, + {file = "simplejson-3.19.3-cp37-cp37m-win_amd64.whl", hash = "sha256:1bd41f2cb1a2c57656ceff67b12d005cb255c728265e222027ad73193a04005a"}, + {file = "simplejson-3.19.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0733ecd95ae03ae718ec74aad818f5af5f3155d596f7b242acbc1621e765e5fb"}, + {file = "simplejson-3.19.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4a0710d1a5e41c4f829caa1572793dd3130c8d65c2b194c24ff29c4c305c26e0"}, + {file = "simplejson-3.19.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1a53a07320c5ff574d8b1a89c937ce33608832f166f39dff0581ac43dc979abd"}, + {file = "simplejson-3.19.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1773cabfba66a6337b547e45dafbd471b09487370bcab75bd28f626520410d29"}, + {file = "simplejson-3.19.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c0104b4b7d2c75ccedbf1d9d5a3bd2daa75e51053935a44ba012e2fd4c43752"}, + {file = "simplejson-3.19.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c49eeb94b8f09dc8a5843c156a22b8bde6aa1ddc65ca8ddc62dddcc001e6a2d"}, + {file = "simplejson-3.19.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dc5c1a85ff388e98ea877042daec3d157b6db0d85bac6ba5498034689793e7e"}, + {file = "simplejson-3.19.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:49549e3d81ab4a58424405aa545602674d8c35c20e986b42bb8668e782a94bac"}, + {file = "simplejson-3.19.3-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:e1a1452ad5723ff129b081e3c8aa4ba56b8734fee4223355ed7b815a7ece69bc"}, + {file = "simplejson-3.19.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:d0d5a63f1768fed7e78cf55712dee81f5a345e34d34224f3507ebf71df2b754d"}, + {file = "simplejson-3.19.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:7e062767ac165df9a46963f5735aa4eee0089ec1e48b3f2ec46182754b96f55e"}, + {file = "simplejson-3.19.3-cp38-cp38-win32.whl", hash = "sha256:56134bbafe458a7b21f6fddbf889d36bec6d903718f4430768e3af822f8e27c2"}, + {file = "simplejson-3.19.3-cp38-cp38-win_amd64.whl", hash = "sha256:bcde83a553a96dc7533736c547bddaa35414a2566ab0ecf7d3964fc4bdb84c11"}, + {file = "simplejson-3.19.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b5587feda2b65a79da985ae6d116daf6428bf7489992badc29fc96d16cd27b05"}, + {file = "simplejson-3.19.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e0d2b00ecbcd1a3c5ea1abc8bb99a26508f758c1759fd01c3be482a3655a176f"}, + {file = "simplejson-3.19.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:32a3ada8f3ea41db35e6d37b86dade03760f804628ec22e4fe775b703d567426"}, + {file = "simplejson-3.19.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f455672f4738b0f47183c5896e3606cd65c9ddee3805a4d18e8c96aa3f47c84"}, + {file = "simplejson-3.19.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b737a5fefedb8333fa50b8db3dcc9b1d18fd6c598f89fa7debff8b46bf4e511"}, + {file = "simplejson-3.19.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb47ee773ce67476a960e2db4a0a906680c54f662521550828c0cc57d0099426"}, + {file = "simplejson-3.19.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eed8cd98a7b24861da9d3d937f5fbfb6657350c547528a117297fe49e3960667"}, + {file = "simplejson-3.19.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:619756f1dd634b5bdf57d9a3914300526c3b348188a765e45b8b08eabef0c94e"}, + {file = "simplejson-3.19.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:dd7230d061e755d60a4d5445bae854afe33444cdb182f3815cff26ac9fb29a15"}, + {file = "simplejson-3.19.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:101a3c8392028cd704a93c7cba8926594e775ca3c91e0bee82144e34190903f1"}, + {file = "simplejson-3.19.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e557712fc79f251673aeb3fad3501d7d4da3a27eff0857af2e1d1afbbcf6685"}, + {file = "simplejson-3.19.3-cp39-cp39-win32.whl", hash = "sha256:0bc5544e3128891bf613b9f71813ee2ec9c11574806f74dd8bb84e5e95bf64a2"}, + {file = "simplejson-3.19.3-cp39-cp39-win_amd64.whl", hash = "sha256:06662392e4913dc8846d6a71a6d5de86db5fba244831abe1dd741d62a4136764"}, + {file = "simplejson-3.19.3-py3-none-any.whl", hash = "sha256:49cc4c7b940d43bd12bf87ec63f28cbc4964fc4e12c031cc8cd01650f43eb94e"}, + {file = "simplejson-3.19.3.tar.gz", hash = "sha256:8e086896c36210ab6050f2f9f095a5f1e03c83fa0e7f296d6cba425411364680"}, ] [[package]] @@ -3806,13 +3667,13 @@ testing = ["Flask (>=1,<2)", "Flask-Sockets (>=0.2,<1)", "Werkzeug (<2)", "black [[package]] name = "social-auth-app-django" -version = "5.4.1" +version = "5.4.2" description = "Python Social Authentication, Django integration." optional = false python-versions = ">=3.8" files = [ - {file = "social-auth-app-django-5.4.1.tar.gz", hash = "sha256:2a43cde559dd34fdc7132417b6c52c780fa99ec2332dee9f405b4763f371c367"}, - {file = "social_auth_app_django-5.4.1-py3-none-any.whl", hash = "sha256:7519f186c63c50f2d364457b236f051338d194bcface55e318a6a705c5213477"}, + {file = "social-auth-app-django-5.4.2.tar.gz", hash = "sha256:c8832c6cf13da6ad76f5613bcda2647d89ae7cfbc5217fadd13477a3406feaa8"}, + {file = "social_auth_app_django-5.4.2-py3-none-any.whl", hash = "sha256:0c041a31707921aef9a930f143183c65d8c7b364381364a50f3f7c6fcc9d62f6"}, ] [package.dependencies] @@ -3821,40 +3682,39 @@ social-auth-core = ">=4.4.1" [[package]] name = "social-auth-core" -version = "4.4.2" +version = "4.5.4" description = "Python social authentication made simple." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "social-auth-core-4.4.2.tar.gz", hash = "sha256:9791d7c7aee2ac8517fe7a2ea2f942a8a5492b3a4ccb44a9b0dacc87d182f2aa"}, - {file = "social_auth_core-4.4.2-py3-none-any.whl", hash = "sha256:ea7a19c46b791b767e95f467881b53c5fd0d1efb40048d9ed3dbc46daa05c954"}, + {file = "social-auth-core-4.5.4.tar.gz", hash = "sha256:d3dbeb0999ffd0e68aa4bd73f2ac698a18133fd11b3fc890e1366f18c8889fac"}, + {file = "social_auth_core-4.5.4-py3-none-any.whl", hash = "sha256:33cf970a623c442376f9d4a86fb187579e4438649daa5b5be993d05e74d7b2db"}, ] [package.dependencies] cryptography = ">=1.4" defusedxml = ">=0.5.0rc1" oauthlib = ">=1.0.3" -PyJWT = ">=2.0.0" +PyJWT = ">=2.7.0" python3-openid = ">=3.0.10" requests = ">=2.9.1" requests-oauthlib = ">=0.6.1" [package.extras] -all = ["cryptography (>=2.1.1)", "python-jose (>=3.0.0)", "python3-saml (>=1.5.0)"] -allpy3 = ["cryptography (>=2.1.1)", "python-jose (>=3.0.0)", "python3-saml (>=1.5.0)"] +all = ["cryptography (>=2.1.1)", "python3-saml (>=1.5.0)"] +allpy3 = ["cryptography (>=2.1.1)", "python3-saml (>=1.5.0)"] azuread = ["cryptography (>=2.1.1)"] -openidconnect = ["python-jose (>=3.0.0)"] saml = ["python3-saml (>=1.5.0)"] [[package]] name = "sqlparse" -version = "0.5.0" +version = "0.5.1" description = "A non-validating SQL parser." optional = false python-versions = ">=3.8" files = [ - {file = "sqlparse-0.5.0-py3-none-any.whl", hash = "sha256:c204494cd97479d0e39f28c93d46c0b2d5959c7b9ab904762ea6c7af211c8663"}, - {file = "sqlparse-0.5.0.tar.gz", hash = "sha256:714d0a4932c059d16189f58ef5411ec2287a4360f17cdd0edd2d09d4c5087c93"}, + {file = "sqlparse-0.5.1-py3-none-any.whl", hash = "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4"}, + {file = "sqlparse-0.5.1.tar.gz", hash = "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e"}, ] [package.extras] @@ -3885,24 +3745,24 @@ files = [ [[package]] name = "tomlkit" -version = "0.13.0" +version = "0.13.2" description = "Style preserving TOML library" optional = false python-versions = ">=3.8" files = [ - {file = "tomlkit-0.13.0-py3-none-any.whl", hash = "sha256:7075d3042d03b80f603482d69bf0c8f345c2b30e41699fd8883227f89972b264"}, - {file = "tomlkit-0.13.0.tar.gz", hash = "sha256:08ad192699734149f5b97b45f1f18dad7eb1b6d16bc72ad0c2335772650d7b72"}, + {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, + {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, ] [[package]] name = "types-toml" -version = "0.10.8.7" +version = "0.10.8.20240310" description = "Typing stubs for toml" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "types-toml-0.10.8.7.tar.gz", hash = "sha256:58b0781c681e671ff0b5c0319309910689f4ab40e8a2431e205d70c94bb6efb1"}, - {file = "types_toml-0.10.8.7-py3-none-any.whl", hash = "sha256:61951da6ad410794c97bec035d59376ce1cbf4453dc9b6f90477e81e4442d631"}, + {file = "types-toml-0.10.8.20240310.tar.gz", hash = "sha256:3d41501302972436a6b8b239c850b26689657e25281b48ff0ec06345b8830331"}, + {file = "types_toml-0.10.8.20240310-py3-none-any.whl", hash = "sha256:627b47775d25fa29977d9c70dc0cbab3f314f32c8d8d0c012f2ef5de7aaec05d"}, ] [[package]] @@ -3918,13 +3778,13 @@ files = [ [[package]] name = "tzdata" -version = "2024.1" +version = "2024.2" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, - {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, + {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, + {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, ] [[package]] @@ -3940,60 +3800,61 @@ files = [ [[package]] name = "urllib3" -version = "1.26.19" +version = "2.0.7" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.7" files = [ - {file = "urllib3-1.26.19-py2.py3-none-any.whl", hash = "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3"}, - {file = "urllib3-1.26.19.tar.gz", hash = "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"}, + {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, + {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, ] [package.extras] -brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "urlman" -version = "2.0.1" +version = "2.0.2" description = "Django URL pattern helpers" optional = false python-versions = "*" files = [ - {file = "urlman-2.0.1-py2.py3-none-any.whl", hash = "sha256:909177485ddbbeada15a21f80155762faf70fc53be31890ff7288e21803f06c7"}, - {file = "urlman-2.0.1.tar.gz", hash = "sha256:3b9c5ac4e447b1e29fa259dc76953d46d711c84b296a0c66c34870e248eb1205"}, + {file = "urlman-2.0.2-py2.py3-none-any.whl", hash = "sha256:2505bf310be424ffa6f4965a6f643ce32dc6194f61a3c5989f2f56453c614814"}, + {file = "urlman-2.0.2.tar.gz", hash = "sha256:231afe89d0d0db358fe7a2626eb39310e5bf5911f3796318955cbe77e1b39601"}, ] [[package]] name = "virtualenv" -version = "20.24.2" +version = "20.26.6" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.2-py3-none-any.whl", hash = "sha256:43a3052be36080548bdee0b42919c88072037d50d56c28bd3f853cbe92b953ff"}, - {file = "virtualenv-20.24.2.tar.gz", hash = "sha256:fd8a78f46f6b99a67b7ec5cf73f92357891a7b3a40fd97637c27f854aae3b9e0"}, + {file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"}, + {file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"}, ] [package.dependencies] distlib = ">=0.3.7,<1" filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<4" +platformdirs = ">=3.9.1,<5" [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "werkzeug" -version = "3.0.3" +version = "3.0.4" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.8" files = [ - {file = "werkzeug-3.0.3-py3-none-any.whl", hash = "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8"}, - {file = "werkzeug-3.0.3.tar.gz", hash = "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18"}, + {file = "werkzeug-3.0.4-py3-none-any.whl", hash = "sha256:02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c"}, + {file = "werkzeug-3.0.4.tar.gz", hash = "sha256:34f2371506b250df4d4f84bfe7b0921e4762525762bbd936614909fe25cd7306"}, ] [package.dependencies] @@ -4004,13 +3865,13 @@ watchdog = ["watchdog (>=2.3)"] [[package]] name = "wheel" -version = "0.41.1" +version = "0.44.0" description = "A built-package format for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "wheel-0.41.1-py3-none-any.whl", hash = "sha256:473219bd4cbedc62cea0cb309089b593e47c15c4a2531015f94e4e3b9a0f6981"}, - {file = "wheel-0.41.1.tar.gz", hash = "sha256:12b911f083e876e10c595779709f8a88a59f45aacc646492a67fe9ef796c1b47"}, + {file = "wheel-0.44.0-py3-none-any.whl", hash = "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f"}, + {file = "wheel-0.44.0.tar.gz", hash = "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49"}, ] [package.extras] @@ -4070,97 +3931,92 @@ resolved_reference = "7cac4330b37442019c666325321d0056f264751b" [[package]] name = "wrapt" -version = "1.15.0" +version = "1.16.0" description = "Module for decorators, wrappers and monkey patching." optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -files = [ - {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"}, - {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"}, - {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"}, - {file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"}, - {file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"}, - {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"}, - {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"}, - {file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"}, - {file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"}, - {file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"}, - {file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"}, - {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"}, - {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"}, - {file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"}, - {file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"}, - {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"}, - {file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"}, - {file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"}, - {file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"}, - {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"}, - {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"}, - {file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"}, - {file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"}, - {file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"}, - {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"}, - {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"}, - {file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"}, - {file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"}, - {file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"}, - {file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"}, - {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"}, - {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"}, - {file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"}, - {file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"}, - {file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"}, - {file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"}, - {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"}, - {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"}, - {file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"}, - {file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"}, - {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"}, - {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"}, +python-versions = ">=3.6" +files = [ + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, + {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, + {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, + {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, + {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, + {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, + {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, + {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, ] [[package]] name = "xmlschema" -version = "2.4.0" +version = "2.5.1" description = "An XML Schema validator and decoder" optional = false python-versions = ">=3.7" files = [ - {file = "xmlschema-2.4.0-py3-none-any.whl", hash = "sha256:dc87be0caaa61f42649899189aab2fd8e0d567f2cf548433ba7b79278d231a4a"}, - {file = "xmlschema-2.4.0.tar.gz", hash = "sha256:d74cd0c10866ac609e1ef94a5a69b018ad16e39077bc6393408b40c6babee793"}, + {file = "xmlschema-2.5.1-py3-none-any.whl", hash = "sha256:ec2b2a15c8896c1fcd14dcee34ca30032b99456c3c43ce793fdb9dca2fb4b869"}, + {file = "xmlschema-2.5.1.tar.gz", hash = "sha256:4f7497de6c8b6dc2c28ad7b9ed6e21d186f4afe248a5bea4f54eedab4da44083"}, ] [package.dependencies] From dbe95fea2c00d736fd3c3b5da3b2f643518f9360 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 7 Oct 2024 13:59:07 +0000 Subject: [PATCH 103/122] Update typing since library upgrade --- api/conftest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/conftest.py b/api/conftest.py index 465c649430ab..88ff11153006 100644 --- a/api/conftest.py +++ b/api/conftest.py @@ -18,6 +18,7 @@ from rest_framework.authtoken.models import Token from rest_framework.test import APIClient from task_processor.task_run_method import TaskRunMethod +from urllib3 import HTTPResponse from urllib3.connectionpool import HTTPConnectionPool from xdist import get_xdist_worker_id @@ -163,7 +164,7 @@ def urlopen_mock( url: str, *args, **kwargs, - ) -> HTTPConnectionPool.ResponseCls: + ) -> HTTPResponse: if self.host in allowed_hosts: return original_urlopen(self, method, url, *args, **kwargs) From cae0b9e0b1aec8298e8b840f94d50110778fc8ff Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 7 Oct 2024 14:10:04 +0000 Subject: [PATCH 104/122] Update lock --- api/poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/poetry.lock b/api/poetry.lock index 852bc3ea4ef3..156015a72b72 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -1406,7 +1406,7 @@ flagsmith-flag-engine = "*" type = "git" url = "https://github.com/Flagsmith/flagsmith-common" reference = "feat/add_workflows_change_request_concerns" -resolved_reference = "963c8a3dd5efc091fe7686134c760e396e87b2db" +resolved_reference = "25c5c7d7e12149e49dbe441e3302061de5aa047b" [[package]] name = "flagsmith-flag-engine" From fc652e4548ee5c921cb3b931d7462376eb480ff9 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 7 Oct 2024 14:38:04 +0000 Subject: [PATCH 105/122] Update lock --- api/poetry.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/poetry.lock b/api/poetry.lock index 156015a72b72..a9eb6ec31c5a 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -1406,7 +1406,7 @@ flagsmith-flag-engine = "*" type = "git" url = "https://github.com/Flagsmith/flagsmith-common" reference = "feat/add_workflows_change_request_concerns" -resolved_reference = "25c5c7d7e12149e49dbe441e3302061de5aa047b" +resolved_reference = "d9d648fd00a63d3d82542a0fc03c24633c1af54a" [[package]] name = "flagsmith-flag-engine" From b2c0668d738fee2bb3d69809bb24d8ae3578d7b1 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Mon, 7 Oct 2024 14:57:38 +0000 Subject: [PATCH 106/122] Update lock --- api/poetry.lock | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/poetry.lock b/api/poetry.lock index a9eb6ec31c5a..50f24e7e9067 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -1399,6 +1399,7 @@ develop = false [package.dependencies] django = "<5.0.0" djangorestframework = "*" +djangorestframework-recursive = "*" drf-writable-nested = "*" flagsmith-flag-engine = "*" @@ -1406,7 +1407,7 @@ flagsmith-flag-engine = "*" type = "git" url = "https://github.com/Flagsmith/flagsmith-common" reference = "feat/add_workflows_change_request_concerns" -resolved_reference = "d9d648fd00a63d3d82542a0fc03c24633c1af54a" +resolved_reference = "5564d1cbc1c9d1ea1a0ba18e944273ecc6373359" [[package]] name = "flagsmith-flag-engine" From 88a67819fc4163e4d9ffe4147d823ce55489bdee Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 23 Oct 2024 15:17:25 +0000 Subject: [PATCH 107/122] Remove stale comment --- api/features/workflows/core/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/api/features/workflows/core/models.py b/api/features/workflows/core/models.py index 782298b99e59..3d1c99bf9d27 100644 --- a/api/features/workflows/core/models.py +++ b/api/features/workflows/core/models.py @@ -78,7 +78,6 @@ class ChangeRequest( null=True, ) - # Change requests get deleted in a delegated task when a project is deleted. project = models.ForeignKey( "projects.Project", on_delete=models.CASCADE, From 3eeb8d343338e508283acb1cdd1ba8c8bf10b6df Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 23 Oct 2024 15:18:03 +0000 Subject: [PATCH 108/122] Update dependancy to tagged version v1.1.0 --- api/poetry.lock | 10 +++++----- api/pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index 7850cf9975dd..33058a84b60f 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -1362,8 +1362,8 @@ flagsmith-flag-engine = "*" [package.source] type = "git" url = "https://github.com/Flagsmith/flagsmith-common" -reference = "feat/add_workflows_change_request_concerns" -resolved_reference = "98e0166d68fc0a4fa0a1309a0f2355e3d89f9267" +reference = "v1.1.0" +resolved_reference = "27fbd8b7d889dc1529df08972a8c1bfaba5a7e03" [[package]] name = "flagsmith-flag-engine" @@ -4060,14 +4060,14 @@ develop = false [package.dependencies] djangorestframework = "*" djangorestframework-recursive = "*" -flagsmith-common = {git = "https://github.com/Flagsmith/flagsmith-common", branch = "feat/add_workflows_change_request_concerns"} +flagsmith-common = {git = "https://github.com/Flagsmith/flagsmith-common", tag = "v1.1.0"} flagsmith-flag-engine = "*" [package.source] type = "git" url = "https://github.com/flagsmith/flagsmith-workflows" reference = "feat/add_change_requests_to_segments" -resolved_reference = "a857e7910a2aeaec2fe9d180894cf9f68ff4969b" +resolved_reference = "4756d1b241133be3cb213eeaf70765031bb2ee2d" [[package]] name = "wrapt" @@ -4186,4 +4186,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.11, <3.13" -content-hash = "c689af63b0148c14da2868478e2ce1dead27e8c777f39269b7633fd50cd223ce" +content-hash = "a53b690d04c413759a3a71c59299ae7be999d2a36b97acfe8327037133b8123a" diff --git a/api/pyproject.toml b/api/pyproject.toml index d455621fc54a..18df84c6e1c8 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -170,7 +170,7 @@ hubspot-api-client = "^8.2.1" djangorestframework-dataclasses = "^1.3.1" pyotp = "^2.9.0" flagsmith-task-processor = { git = "https://github.com/Flagsmith/flagsmith-task-processor", tag = "v1.0.2" } -flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common", branch = "feat/add_workflows_change_request_concerns" } +flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common", tag = "v1.1.0" } tzdata = "^2024.1" djangorestframework-simplejwt = "^5.3.1" From 34fc147e18cb51f0ee2beeb2318e8d25c77b1bce Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 23 Oct 2024 15:18:42 +0000 Subject: [PATCH 109/122] Bulk update and select related project --- .../core/migrations/0011_add_project_to_change_requests.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py b/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py index 088d84e547f8..d5df27aeca58 100644 --- a/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py +++ b/api/features/workflows/core/migrations/0011_add_project_to_change_requests.py @@ -7,11 +7,14 @@ def set_project_for_existing_change_requests(apps, schema_model): ChangeRequest = apps.get_model("workflows_core", "ChangeRequest") + change_requests = [] for change_request in ChangeRequest.objects.filter( environment_id__isnull=False - ).select_related("environment"): + ).select_related("environment", "environment__project"): change_request.project = change_request.environment.project - change_request.save() + change_requests.append(change_request) + + ChangeRequest.objects.bulk_update(change_requests, ["project"]) class Migration(migrations.Migration): From 790ebb1c30cd71b13c4ce7a364dc6be27e4218fe Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 23 Oct 2024 15:43:24 +0000 Subject: [PATCH 110/122] Remove environments permissions constants --- api/environments/permissions/constants.py | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 api/environments/permissions/constants.py diff --git a/api/environments/permissions/constants.py b/api/environments/permissions/constants.py deleted file mode 100644 index 90b4f6a192ea..000000000000 --- a/api/environments/permissions/constants.py +++ /dev/null @@ -1,10 +0,0 @@ -# Maintain a list of permissions here -VIEW_ENVIRONMENT = "VIEW_ENVIRONMENT" -UPDATE_FEATURE_STATE = "UPDATE_FEATURE_STATE" -MANAGE_IDENTITIES = "MANAGE_IDENTITIES" -VIEW_IDENTITIES = "VIEW_IDENTITIES" -CREATE_CHANGE_REQUEST = "CREATE_CHANGE_REQUEST" -APPROVE_CHANGE_REQUEST = "APPROVE_CHANGE_REQUEST" -MANAGE_SEGMENT_OVERRIDES = "MANAGE_SEGMENT_OVERRIDES" - -TAG_SUPPORTED_PERMISSIONS = [UPDATE_FEATURE_STATE] From 4f352df6d6777e9caeb037adacb801fc5757be7e Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 23 Oct 2024 15:44:53 +0000 Subject: [PATCH 111/122] Update to common library for environments permissions constants --- api/conftest.py | 10 +-- api/e2etests/e2e_seed_data.py | 10 +-- api/edge_api/identities/permissions.py | 8 +-- api/edge_api/identities/views.py | 5 +- api/environments/identities/traits/views.py | 5 +- api/environments/identities/views.py | 5 +- .../migrations/0010_auto_20200219_2343.py | 22 +++++-- ...002_add_update_feature_state_permission.py | 4 +- .../0003_add_manage_identities_permission.py | 2 +- .../0004_add_change_request_permissions.py | 11 ++-- .../0005_add_view_identity_permissions.py | 5 +- ...add_manage_segment_overrides_permission.py | 11 +++- api/environments/permissions/permissions.py | 2 +- api/features/feature_segments/permissions.py | 2 +- api/features/feature_segments/serializers.py | 2 +- api/features/permissions.py | 16 ++--- api/features/versioning/permissions.py | 14 ++-- api/features/versioning/views.py | 2 +- api/integrations/common/views.py | 2 +- api/permissions/migrations/0001_initial.py | 64 +++++++++++++++---- .../test_edge_api_identities_views.py | 10 +-- .../edge_api/identities/test_permissions.py | 3 +- ...st_unit_identities_feature_states_views.py | 8 +-- .../identities/test_unit_identities_views.py | 5 +- .../identities/traits/test_traits_views.py | 10 +-- ...nit_environments_permissions_migrations.py | 5 +- .../test_unit_environments_views.py | 2 +- ..._unit_environments_feature_states_views.py | 8 +-- .../test_unit_environments_views.py | 2 +- .../test_unit_feature_segments_views.py | 10 +-- ...t_unit_feature_external_resources_views.py | 2 +- .../unit/features/test_unit_features_views.py | 10 +-- .../versioning/test_unit_versioning_views.py | 8 +-- ...est_get_permitted_environments_for_user.py | 6 +- .../test_unit_permissions_calculator.py | 4 +- 35 files changed, 167 insertions(+), 128 deletions(-) diff --git a/api/conftest.py b/api/conftest.py index 12e1c2526880..22691cd4619f 100644 --- a/api/conftest.py +++ b/api/conftest.py @@ -5,6 +5,11 @@ import boto3 import pytest +from common.environments.permissions import ( + MANAGE_IDENTITIES, + VIEW_ENVIRONMENT, + VIEW_IDENTITIES, +) from django.contrib.contenttypes.models import ContentType from django.core.cache import caches from django.db.backends.base.creation import TEST_DATABASE_PREFIX @@ -27,11 +32,6 @@ from environments.identities.models import Identity from environments.identities.traits.models import Trait from environments.models import Environment, EnvironmentAPIKey -from environments.permissions.constants import ( - MANAGE_IDENTITIES, - VIEW_ENVIRONMENT, - VIEW_IDENTITIES, -) from environments.permissions.models import ( UserEnvironmentPermission, UserPermissionGroupEnvironmentPermission, diff --git a/api/e2etests/e2e_seed_data.py b/api/e2etests/e2e_seed_data.py index eba97bd65cb8..6a60527abf80 100644 --- a/api/e2etests/e2e_seed_data.py +++ b/api/e2etests/e2e_seed_data.py @@ -1,14 +1,14 @@ +from common.environments.permissions import ( + UPDATE_FEATURE_STATE, + VIEW_ENVIRONMENT, + VIEW_IDENTITIES, +) from django.conf import settings from flag_engine.identities.models import IdentityModel as EngineIdentity from edge_api.identities.models import EdgeIdentity from environments.identities.models import Identity from environments.models import Environment -from environments.permissions.constants import ( - UPDATE_FEATURE_STATE, - VIEW_ENVIRONMENT, - VIEW_IDENTITIES, -) from environments.permissions.models import UserEnvironmentPermission from organisations.models import Organisation, OrganisationRole, Subscription from organisations.permissions.models import UserOrganisationPermission diff --git a/api/edge_api/identities/permissions.py b/api/edge_api/identities/permissions.py index fd67d235589c..580bdd81e14c 100644 --- a/api/edge_api/identities/permissions.py +++ b/api/edge_api/identities/permissions.py @@ -1,14 +1,14 @@ from contextlib import suppress +from common.environments.permissions import ( + UPDATE_FEATURE_STATE, + VIEW_IDENTITIES, +) from django.http import HttpRequest from django.views import View from rest_framework.permissions import BasePermission from environments.models import Environment -from environments.permissions.constants import ( - UPDATE_FEATURE_STATE, - VIEW_IDENTITIES, -) class EdgeIdentityWithIdentifierViewPermissions(BasePermission): diff --git a/api/edge_api/identities/views.py b/api/edge_api/identities/views.py index ac2994277e89..d49ae3ec4250 100644 --- a/api/edge_api/identities/views.py +++ b/api/edge_api/identities/views.py @@ -3,6 +3,7 @@ import typing import pydantic +from common.environments.permissions import MANAGE_IDENTITIES, VIEW_IDENTITIES from django.shortcuts import get_object_or_404 from django.utils.decorators import method_decorator from drf_yasg.utils import swagger_auto_schema @@ -51,10 +52,6 @@ IdentityAllFeatureStatesSerializer, ) from environments.models import Environment -from environments.permissions.constants import ( - MANAGE_IDENTITIES, - VIEW_IDENTITIES, -) from environments.permissions.permissions import NestedEnvironmentPermissions from features.models import FeatureState from features.permissions import IdentityFeatureStatePermissions diff --git a/api/environments/identities/traits/views.py b/api/environments/identities/traits/views.py index 201512643e65..4b434ce539fd 100644 --- a/api/environments/identities/traits/views.py +++ b/api/environments/identities/traits/views.py @@ -1,3 +1,4 @@ +from common.environments.permissions import MANAGE_IDENTITIES, VIEW_IDENTITIES from django.conf import settings from django.core.exceptions import BadRequest from django.db.models import Q @@ -21,10 +22,6 @@ TraitSerializerBasic, TraitSerializerFull, ) -from environments.permissions.constants import ( - MANAGE_IDENTITIES, - VIEW_IDENTITIES, -) from environments.permissions.permissions import ( EnvironmentKeyPermissions, NestedEnvironmentPermissions, diff --git a/api/environments/identities/views.py b/api/environments/identities/views.py index a86d240f73d1..49f0f365ebac 100644 --- a/api/environments/identities/views.py +++ b/api/environments/identities/views.py @@ -1,6 +1,7 @@ import typing from collections import namedtuple +from common.environments.permissions import MANAGE_IDENTITIES, VIEW_IDENTITIES from core.constants import FLAGSMITH_UPDATED_AT_HEADER from core.request_origin import RequestOrigin from django.conf import settings @@ -22,10 +23,6 @@ SDKIdentitiesResponseSerializer, ) from environments.models import Environment -from environments.permissions.constants import ( - MANAGE_IDENTITIES, - VIEW_IDENTITIES, -) from environments.permissions.permissions import NestedEnvironmentPermissions from environments.sdk.serializers import ( IdentifyWithTraitsSerializer, diff --git a/api/environments/migrations/0010_auto_20200219_2343.py b/api/environments/migrations/0010_auto_20200219_2343.py index 119513c81c84..48c221f0e0b7 100644 --- a/api/environments/migrations/0010_auto_20200219_2343.py +++ b/api/environments/migrations/0010_auto_20200219_2343.py @@ -1,7 +1,14 @@ # Generated by Django 2.2.10 on 2020-02-19 23:43 +from common.environments.permissions import ( + APPROVE_CHANGE_REQUEST, + CREATE_CHANGE_REQUEST, + MANAGE_IDENTITIES, + UPDATE_FEATURE_STATE, + VIEW_ENVIRONMENT, +) from django.db import migrations -from environments.permissions.constants import VIEW_ENVIRONMENT, UPDATE_FEATURE_STATE, MANAGE_IDENTITIES, CREATE_CHANGE_REQUEST, APPROVE_CHANGE_REQUEST + ENVIRONMENT_PERMISSIONS = [ (VIEW_ENVIRONMENT, "View permission for the given environment."), (UPDATE_FEATURE_STATE, "Update the state or value for a given feature state."), @@ -16,12 +23,15 @@ ), ] + def create_default_permissions(apps, schema_editor): - EnvironmentPermission = apps.get_model('environments', 'EnvironmentPermission') + EnvironmentPermission = apps.get_model("environments", "EnvironmentPermission") environment_permissions = [] for permission in ENVIRONMENT_PERMISSIONS: - environment_permissions.append(EnvironmentPermission(key=permission[0], description=permission[1])) + environment_permissions.append( + EnvironmentPermission(key=permission[0], description=permission[1]) + ) EnvironmentPermission.objects.bulk_create(environment_permissions) @@ -29,9 +39,11 @@ def create_default_permissions(apps, schema_editor): class Migration(migrations.Migration): dependencies = [ - ('environments', '0009_auto_20200219_1922'), + ("environments", "0009_auto_20200219_1922"), ] operations = [ - migrations.RunPython(create_default_permissions, reverse_code=lambda *args: None) + migrations.RunPython( + create_default_permissions, reverse_code=lambda *args: None + ) ] diff --git a/api/environments/permissions/migrations/0002_add_update_feature_state_permission.py b/api/environments/permissions/migrations/0002_add_update_feature_state_permission.py index 2d01699d970e..8833af04f959 100644 --- a/api/environments/permissions/migrations/0002_add_update_feature_state_permission.py +++ b/api/environments/permissions/migrations/0002_add_update_feature_state_permission.py @@ -1,8 +1,8 @@ # Generated by Django 2.2.24 on 2021-12-07 17:48 +from common.environments.permissions import UPDATE_FEATURE_STATE from django.db import migrations -from environments.permissions.constants import UPDATE_FEATURE_STATE from permissions.models import ENVIRONMENT_PERMISSION_TYPE @@ -26,7 +26,7 @@ class Migration(migrations.Migration): dependencies = [ ("environment_permissions", "0001_initial"), - ("features", "0035_auto_20211109_0603") + ("features", "0035_auto_20211109_0603"), ] operations = [ diff --git a/api/environments/permissions/migrations/0003_add_manage_identities_permission.py b/api/environments/permissions/migrations/0003_add_manage_identities_permission.py index 958d51a08e5b..27a4ac2e3626 100644 --- a/api/environments/permissions/migrations/0003_add_manage_identities_permission.py +++ b/api/environments/permissions/migrations/0003_add_manage_identities_permission.py @@ -1,8 +1,8 @@ # Generated by Django 2.2.24 on 2021-12-07 17:48 +from common.environments.permissions import MANAGE_IDENTITIES from django.db import migrations -from environments.permissions.constants import MANAGE_IDENTITIES from permissions.models import ENVIRONMENT_PERMISSION_TYPE diff --git a/api/environments/permissions/migrations/0004_add_change_request_permissions.py b/api/environments/permissions/migrations/0004_add_change_request_permissions.py index f9c637fed995..5cf1fea24f36 100644 --- a/api/environments/permissions/migrations/0004_add_change_request_permissions.py +++ b/api/environments/permissions/migrations/0004_add_change_request_permissions.py @@ -1,16 +1,15 @@ # Generated by Django 3.2.15 on 2022-09-13 19:18 import typing -from django.db import migrations - -from environments.permissions.constants import ( - CREATE_CHANGE_REQUEST, +from common.environments.permissions import ( APPROVE_CHANGE_REQUEST, + CREATE_CHANGE_REQUEST, UPDATE_FEATURE_STATE, ) -from permissions.models import ENVIRONMENT_PERMISSION_TYPE - from core.migration_helpers import create_new_environment_permissions +from django.db import migrations + +from permissions.models import ENVIRONMENT_PERMISSION_TYPE def add_change_request_permissions(apps, schema_editor): diff --git a/api/environments/permissions/migrations/0005_add_view_identity_permissions.py b/api/environments/permissions/migrations/0005_add_view_identity_permissions.py index 4c852f4bea1d..4c7ef9fbb805 100644 --- a/api/environments/permissions/migrations/0005_add_view_identity_permissions.py +++ b/api/environments/permissions/migrations/0005_add_view_identity_permissions.py @@ -1,9 +1,8 @@ # Generated by Django 3.2.16 on 2022-12-19 10:18 -from django.db import migrations - -from environments.permissions.constants import VIEW_IDENTITIES, MANAGE_IDENTITIES +from common.environments.permissions import MANAGE_IDENTITIES, VIEW_IDENTITIES from core.migration_helpers import create_new_environment_permissions +from django.db import migrations from permissions.models import ENVIRONMENT_PERMISSION_TYPE diff --git a/api/environments/permissions/migrations/0008_add_manage_segment_overrides_permission.py b/api/environments/permissions/migrations/0008_add_manage_segment_overrides_permission.py index 4ac562b6ceeb..313946651d58 100644 --- a/api/environments/permissions/migrations/0008_add_manage_segment_overrides_permission.py +++ b/api/environments/permissions/migrations/0008_add_manage_segment_overrides_permission.py @@ -1,11 +1,15 @@ # Generated by Django 3.2.20 on 2023-11-01 19:54 -from django.db import migrations -from environments.permissions.constants import MANAGE_SEGMENT_OVERRIDES, UPDATE_FEATURE_STATE +from common.environments.permissions import ( + MANAGE_SEGMENT_OVERRIDES, + UPDATE_FEATURE_STATE, +) from core.migration_helpers import create_new_environment_permissions +from django.db import migrations from permissions.models import ENVIRONMENT_PERMISSION_TYPE + def add_manage_segment_overrides_permission(apps, schema_editor): PermissionModel = apps.get_model("permissions", "PermissionModel") UserEnvironmentPermission = apps.get_model( @@ -41,10 +45,11 @@ def remove_manage_segment_overrides_permission(apps, schema_editor): PermissionModel = apps.get_model("permissions", "PermissionModel") PermissionModel.objects.filter(key=MANAGE_SEGMENT_OVERRIDES).delete() + class Migration(migrations.Migration): dependencies = [ - ('environment_permissions', '0007_add_unique_permission_constraint'), + ("environment_permissions", "0007_add_unique_permission_constraint"), ] operations = [ diff --git a/api/environments/permissions/permissions.py b/api/environments/permissions/permissions.py index 020b7a065249..7a4acc4fcb47 100644 --- a/api/environments/permissions/permissions.py +++ b/api/environments/permissions/permissions.py @@ -1,11 +1,11 @@ import typing +from common.environments.permissions import VIEW_ENVIRONMENT from django.db.models import Model, Q from rest_framework import exceptions from rest_framework.permissions import BasePermission, IsAuthenticated from environments.models import Environment -from environments.permissions.constants import VIEW_ENVIRONMENT from projects.models import Project from projects.permissions import CREATE_ENVIRONMENT diff --git a/api/features/feature_segments/permissions.py b/api/features/feature_segments/permissions.py index 134e0320e89f..f057754e4f89 100644 --- a/api/features/feature_segments/permissions.py +++ b/api/features/feature_segments/permissions.py @@ -1,9 +1,9 @@ from contextlib import suppress +from common.environments.permissions import MANAGE_SEGMENT_OVERRIDES from rest_framework.permissions import IsAuthenticated from environments.models import Environment -from environments.permissions.constants import MANAGE_SEGMENT_OVERRIDES class FeatureSegmentPermissions(IsAuthenticated): diff --git a/api/features/feature_segments/serializers.py b/api/features/feature_segments/serializers.py index 1064d807dad1..0919328724c9 100644 --- a/api/features/feature_segments/serializers.py +++ b/api/features/feature_segments/serializers.py @@ -1,3 +1,4 @@ +from common.environments.permissions import MANAGE_SEGMENT_OVERRIDES from common.features.serializers import ( CreateSegmentOverrideFeatureSegmentSerializer, ) @@ -5,7 +6,6 @@ from rest_framework import serializers from rest_framework.exceptions import PermissionDenied -from environments.permissions.constants import MANAGE_SEGMENT_OVERRIDES from features.feature_segments.limits import ( SEGMENT_OVERRIDE_LIMIT_EXCEEDED_MESSAGE, exceeds_segment_override_limit, diff --git a/api/features/permissions.py b/api/features/permissions.py index 57cd146fe153..b1deb32a42f2 100644 --- a/api/features/permissions.py +++ b/api/features/permissions.py @@ -1,19 +1,19 @@ from contextlib import suppress +from common.environments.permissions import MANAGE_SEGMENT_OVERRIDES +from common.environments.permissions import ( + TAG_SUPPORTED_PERMISSIONS as TAG_SUPPORTED_ENVIRONMENT_PERMISSIONS, +) +from common.environments.permissions import ( + UPDATE_FEATURE_STATE, + VIEW_ENVIRONMENT, +) from django.shortcuts import get_object_or_404 from rest_framework.permissions import IsAuthenticated from rest_framework.request import Request from rest_framework.viewsets import GenericViewSet from environments.models import Environment -from environments.permissions.constants import MANAGE_SEGMENT_OVERRIDES -from environments.permissions.constants import ( - TAG_SUPPORTED_PERMISSIONS as TAG_SUPPORTED_ENVIRONMENT_PERMISSIONS, -) -from environments.permissions.constants import ( - UPDATE_FEATURE_STATE, - VIEW_ENVIRONMENT, -) from features.models import Feature, FeatureState from projects.models import Project from projects.permissions import CREATE_FEATURE, DELETE_FEATURE diff --git a/api/features/versioning/permissions.py b/api/features/versioning/permissions.py index 0023ff33b6f6..b0a955c31605 100644 --- a/api/features/versioning/permissions.py +++ b/api/features/versioning/permissions.py @@ -1,15 +1,15 @@ -from rest_framework.permissions import BasePermission -from rest_framework.request import Request -from rest_framework.viewsets import GenericViewSet - -from environments.models import Environment -from environments.permissions.constants import ( +from common.environments.permissions import ( TAG_SUPPORTED_PERMISSIONS as TAG_SUPPORTED_ENVIRONMENT_PERMISSIONS, ) -from environments.permissions.constants import ( +from common.environments.permissions import ( UPDATE_FEATURE_STATE, VIEW_ENVIRONMENT, ) +from rest_framework.permissions import BasePermission +from rest_framework.request import Request +from rest_framework.viewsets import GenericViewSet + +from environments.models import Environment from features.models import Feature, FeatureState from features.versioning.models import EnvironmentFeatureVersion diff --git a/api/features/versioning/views.py b/api/features/versioning/views.py index 184fb7266a7f..07840a23bb79 100644 --- a/api/features/versioning/views.py +++ b/api/features/versioning/views.py @@ -1,3 +1,4 @@ +from common.environments.permissions import VIEW_ENVIRONMENT from django.db.models import BooleanField, ExpressionWrapper, Q from django.shortcuts import get_object_or_404 from django.utils import timezone @@ -18,7 +19,6 @@ from rest_framework.viewsets import GenericViewSet from environments.models import Environment -from environments.permissions.constants import VIEW_ENVIRONMENT from features.models import Feature, FeatureState from features.serializers import ( CustomCreateSegmentOverrideFeatureStateSerializer, diff --git a/api/integrations/common/views.py b/api/integrations/common/views.py index f4ed2d230608..19b4b8765742 100644 --- a/api/integrations/common/views.py +++ b/api/integrations/common/views.py @@ -1,3 +1,4 @@ +from common.environments.permissions import VIEW_ENVIRONMENT from django.db.models import QuerySet from django.shortcuts import get_object_or_404 from rest_framework import viewsets @@ -7,7 +8,6 @@ from rest_framework.serializers import BaseSerializer from environments.models import Environment -from environments.permissions.constants import VIEW_ENVIRONMENT from environments.permissions.permissions import NestedEnvironmentPermissions from organisations.permissions.permissions import ( NestedOrganisationEntityPermission, diff --git a/api/permissions/migrations/0001_initial.py b/api/permissions/migrations/0001_initial.py index 33a0f25ce2d8..e78d60227786 100644 --- a/api/permissions/migrations/0001_initial.py +++ b/api/permissions/migrations/0001_initial.py @@ -1,10 +1,20 @@ # Generated by Django 2.2.10 on 2020-02-20 00:24 +from common.environments.permissions import ( + APPROVE_CHANGE_REQUEST, + CREATE_CHANGE_REQUEST, + MANAGE_IDENTITIES, + UPDATE_FEATURE_STATE, + VIEW_ENVIRONMENT, +) from django.db import migrations, models -from permissions.models import PROJECT_PERMISSION_TYPE, ENVIRONMENT_PERMISSION_TYPE +from permissions.models import ( + ENVIRONMENT_PERMISSION_TYPE, + PROJECT_PERMISSION_TYPE, +) from projects.permissions import PROJECT_PERMISSIONS -from environments.permissions.constants import VIEW_ENVIRONMENT, UPDATE_FEATURE_STATE, MANAGE_IDENTITIES, CREATE_CHANGE_REQUEST, APPROVE_CHANGE_REQUEST + ENVIRONMENT_PERMISSIONS = [ (VIEW_ENVIRONMENT, "View permission for the given environment."), (UPDATE_FEATURE_STATE, "Update the state or value for a given feature state."), @@ -21,23 +31,33 @@ def insert_default_project_permissions(apps, schema_model): - PermissionModel = apps.get_model('permissions', 'PermissionModel') + PermissionModel = apps.get_model("permissions", "PermissionModel") project_permissions = [] for permission in PROJECT_PERMISSIONS: project_permissions.append( - PermissionModel(key=permission[0], description=permission[1], type=PROJECT_PERMISSION_TYPE)) + PermissionModel( + key=permission[0], + description=permission[1], + type=PROJECT_PERMISSION_TYPE, + ) + ) PermissionModel.objects.bulk_create(project_permissions) def insert_default_environment_permissions(apps, schema_model): - PermissionModel = apps.get_model('permissions', 'PermissionModel') + PermissionModel = apps.get_model("permissions", "PermissionModel") environment_permissions = [] for permission in ENVIRONMENT_PERMISSIONS: environment_permissions.append( - PermissionModel(key=permission[0], description=permission[1], type=ENVIRONMENT_PERMISSION_TYPE)) + PermissionModel( + key=permission[0], + description=permission[1], + type=ENVIRONMENT_PERMISSION_TYPE, + ) + ) PermissionModel.objects.bulk_create(environment_permissions) @@ -46,18 +66,34 @@ class Migration(migrations.Migration): initial = True - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( - name='PermissionModel', + name="PermissionModel", fields=[ - ('key', models.CharField(max_length=100, primary_key=True, serialize=False)), - ('description', models.TextField()), - ('type', models.CharField(choices=[('PROJECT', 'Project'), ('ENVIRONMENT', 'Environment')], max_length=100, null=True)), + ( + "key", + models.CharField(max_length=100, primary_key=True, serialize=False), + ), + ("description", models.TextField()), + ( + "type", + models.CharField( + choices=[ + ("PROJECT", "Project"), + ("ENVIRONMENT", "Environment"), + ], + max_length=100, + null=True, + ), + ), ], ), - migrations.RunPython(insert_default_project_permissions, reverse_code=lambda *args: None), - migrations.RunPython(insert_default_environment_permissions, reverse_code=lambda *args: None), + migrations.RunPython( + insert_default_project_permissions, reverse_code=lambda *args: None + ), + migrations.RunPython( + insert_default_environment_permissions, reverse_code=lambda *args: None + ), ] diff --git a/api/tests/unit/edge_api/identities/test_edge_api_identities_views.py b/api/tests/unit/edge_api/identities/test_edge_api_identities_views.py index 6aaea120e978..8f0d3c5c1a87 100644 --- a/api/tests/unit/edge_api/identities/test_edge_api_identities_views.py +++ b/api/tests/unit/edge_api/identities/test_edge_api_identities_views.py @@ -1,3 +1,8 @@ +from common.environments.permissions import ( + MANAGE_IDENTITIES, + VIEW_ENVIRONMENT, + VIEW_IDENTITIES, +) from django.urls import reverse from pytest_mock import MockerFixture from rest_framework import status @@ -7,11 +12,6 @@ from edge_api.identities.models import EdgeIdentity from edge_api.identities.views import EdgeIdentityViewSet from environments.models import Environment -from environments.permissions.constants import ( - MANAGE_IDENTITIES, - VIEW_ENVIRONMENT, - VIEW_IDENTITIES, -) from environments.permissions.permissions import NestedEnvironmentPermissions from features.models import Feature from tests.types import WithEnvironmentPermissionsCallable diff --git a/api/tests/unit/edge_api/identities/test_permissions.py b/api/tests/unit/edge_api/identities/test_permissions.py index 32361dcfa4ee..6bb7c4de592d 100644 --- a/api/tests/unit/edge_api/identities/test_permissions.py +++ b/api/tests/unit/edge_api/identities/test_permissions.py @@ -1,7 +1,8 @@ +from common.environments.permissions import UPDATE_FEATURE_STATE + from edge_api.identities.permissions import ( EdgeIdentityWithIdentifierViewPermissions, ) -from environments.permissions.constants import UPDATE_FEATURE_STATE def test_edge_identity_with_identifier_view_permissions_has_permissions_calls_has_environment_permission( diff --git a/api/tests/unit/environments/identities/test_unit_identities_feature_states_views.py b/api/tests/unit/environments/identities/test_unit_identities_feature_states_views.py index a2d3c3185c03..eae6add8bcd5 100644 --- a/api/tests/unit/environments/identities/test_unit_identities_feature_states_views.py +++ b/api/tests/unit/environments/identities/test_unit_identities_feature_states_views.py @@ -1,6 +1,10 @@ import json import pytest +from common.environments.permissions import ( + UPDATE_FEATURE_STATE, + VIEW_ENVIRONMENT, +) from core.constants import STRING from django.test import Client from django.urls import reverse @@ -8,10 +12,6 @@ from environments.identities.models import Identity from environments.models import Environment -from environments.permissions.constants import ( - UPDATE_FEATURE_STATE, - VIEW_ENVIRONMENT, -) from features.models import Feature, FeatureState, FeatureStateValue from features.multivariate.models import ( MultivariateFeatureOption, diff --git a/api/tests/unit/environments/identities/test_unit_identities_views.py b/api/tests/unit/environments/identities/test_unit_identities_views.py index b1e31cdb50b2..e62c12dbf88e 100644 --- a/api/tests/unit/environments/identities/test_unit_identities_views.py +++ b/api/tests/unit/environments/identities/test_unit_identities_views.py @@ -4,6 +4,7 @@ from unittest import mock import pytest +from common.environments.permissions import MANAGE_IDENTITIES, VIEW_IDENTITIES from core.constants import FLAGSMITH_UPDATED_AT_HEADER, STRING from django.test import override_settings from django.urls import reverse @@ -21,10 +22,6 @@ from environments.identities.traits.models import Trait from environments.identities.views import IdentityViewSet from environments.models import Environment, EnvironmentAPIKey -from environments.permissions.constants import ( - MANAGE_IDENTITIES, - VIEW_IDENTITIES, -) from environments.permissions.permissions import NestedEnvironmentPermissions from features.models import Feature, FeatureSegment, FeatureState from integrations.amplitude.models import AmplitudeConfiguration diff --git a/api/tests/unit/environments/identities/traits/test_traits_views.py b/api/tests/unit/environments/identities/traits/test_traits_views.py index 321b76915463..f52c09e09b38 100644 --- a/api/tests/unit/environments/identities/traits/test_traits_views.py +++ b/api/tests/unit/environments/identities/traits/test_traits_views.py @@ -1,6 +1,11 @@ import json from unittest import mock +from common.environments.permissions import ( + MANAGE_IDENTITIES, + VIEW_ENVIRONMENT, + VIEW_IDENTITIES, +) from core.constants import INTEGER, STRING from django.test import override_settings from django.urls import reverse @@ -15,11 +20,6 @@ from environments.identities.traits.models import Trait from environments.identities.traits.views import TraitViewSet from environments.models import Environment, EnvironmentAPIKey -from environments.permissions.constants import ( - MANAGE_IDENTITIES, - VIEW_ENVIRONMENT, - VIEW_IDENTITIES, -) from environments.permissions.models import UserEnvironmentPermission from environments.permissions.permissions import NestedEnvironmentPermissions from organisations.models import Organisation diff --git a/api/tests/unit/environments/permissions/test_unit_environments_permissions_migrations.py b/api/tests/unit/environments/permissions/test_unit_environments_permissions_migrations.py index 6a6a33b726e9..3cc3b0b557f6 100644 --- a/api/tests/unit/environments/permissions/test_unit_environments_permissions_migrations.py +++ b/api/tests/unit/environments/permissions/test_unit_environments_permissions_migrations.py @@ -1,13 +1,12 @@ import pytest -from django.conf import settings - -from environments.permissions.constants import ( +from common.environments.permissions import ( APPROVE_CHANGE_REQUEST, CREATE_CHANGE_REQUEST, MANAGE_IDENTITIES, UPDATE_FEATURE_STATE, VIEW_IDENTITIES, ) +from django.conf import settings if settings.SKIP_MIGRATION_TESTS is True: pytest.skip( diff --git a/api/tests/unit/environments/permissions/test_unit_environments_views.py b/api/tests/unit/environments/permissions/test_unit_environments_views.py index 9001397f57d5..78e5847f1fac 100644 --- a/api/tests/unit/environments/permissions/test_unit_environments_views.py +++ b/api/tests/unit/environments/permissions/test_unit_environments_views.py @@ -1,12 +1,12 @@ import json import pytest +from common.environments.permissions import VIEW_ENVIRONMENT from django.urls import reverse from rest_framework import status from rest_framework.test import APIClient from environments.models import Environment -from environments.permissions.constants import VIEW_ENVIRONMENT from environments.permissions.models import ( EnvironmentPermissionModel, UserEnvironmentPermission, diff --git a/api/tests/unit/environments/test_unit_environments_feature_states_views.py b/api/tests/unit/environments/test_unit_environments_feature_states_views.py index ec335dcf8cb7..205c189ab899 100644 --- a/api/tests/unit/environments/test_unit_environments_feature_states_views.py +++ b/api/tests/unit/environments/test_unit_environments_feature_states_views.py @@ -1,13 +1,13 @@ import json import pytest -from django.urls import reverse -from rest_framework import status - -from environments.permissions.constants import ( +from common.environments.permissions import ( UPDATE_FEATURE_STATE, VIEW_ENVIRONMENT, ) +from django.urls import reverse +from rest_framework import status + from tests.unit.environments.helpers import get_environment_user_client diff --git a/api/tests/unit/environments/test_unit_environments_views.py b/api/tests/unit/environments/test_unit_environments_views.py index 39486bd3c06d..1929ff8ae396 100644 --- a/api/tests/unit/environments/test_unit_environments_views.py +++ b/api/tests/unit/environments/test_unit_environments_views.py @@ -2,6 +2,7 @@ from unittest import mock import pytest +from common.environments.permissions import VIEW_ENVIRONMENT from core.constants import STRING from django.conf import settings from django.contrib.contenttypes.models import ContentType @@ -18,7 +19,6 @@ from environments.identities.models import Identity from environments.identities.traits.models import Trait from environments.models import Environment, EnvironmentAPIKey, Webhook -from environments.permissions.constants import VIEW_ENVIRONMENT from environments.permissions.models import UserEnvironmentPermission from features.models import Feature, FeatureState from features.versioning.models import EnvironmentFeatureVersion diff --git a/api/tests/unit/features/feature_segments/test_unit_feature_segments_views.py b/api/tests/unit/features/feature_segments/test_unit_feature_segments_views.py index f6a68460015e..0f9c5b76d26a 100644 --- a/api/tests/unit/features/feature_segments/test_unit_feature_segments_views.py +++ b/api/tests/unit/features/feature_segments/test_unit_feature_segments_views.py @@ -1,6 +1,11 @@ import json import pytest +from common.environments.permissions import ( + MANAGE_SEGMENT_OVERRIDES, + UPDATE_FEATURE_STATE, + VIEW_ENVIRONMENT, +) from django.conf import settings from django.urls import reverse from pytest_django import DjangoAssertNumQueries @@ -12,11 +17,6 @@ from audit.models import AuditLog from audit.related_object_type import RelatedObjectType from environments.models import Environment -from environments.permissions.constants import ( - MANAGE_SEGMENT_OVERRIDES, - UPDATE_FEATURE_STATE, - VIEW_ENVIRONMENT, -) from features.models import Feature, FeatureSegment, FeatureState from features.versioning.models import EnvironmentFeatureVersion from projects.models import Project, UserProjectPermission diff --git a/api/tests/unit/features/test_unit_feature_external_resources_views.py b/api/tests/unit/features/test_unit_feature_external_resources_views.py index d6ba8c501b14..90d136954f79 100644 --- a/api/tests/unit/features/test_unit_feature_external_resources_views.py +++ b/api/tests/unit/features/test_unit_feature_external_resources_views.py @@ -4,6 +4,7 @@ import pytest import responses import simplejson as json +from common.environments.permissions import UPDATE_FEATURE_STATE from django.core.serializers.json import DjangoJSONEncoder from django.urls import reverse from django.utils.formats import get_format @@ -12,7 +13,6 @@ from rest_framework.test import APIClient from environments.models import Environment -from environments.permissions.constants import UPDATE_FEATURE_STATE from features.feature_external_resources.models import FeatureExternalResource from features.models import Feature, FeatureSegment, FeatureState from features.serializers import ( diff --git a/api/tests/unit/features/test_unit_features_views.py b/api/tests/unit/features/test_unit_features_views.py index 02705c03c8ef..3ea5296da5cb 100644 --- a/api/tests/unit/features/test_unit_features_views.py +++ b/api/tests/unit/features/test_unit_features_views.py @@ -6,6 +6,11 @@ import pytest import pytz from app_analytics.dataclasses import FeatureEvaluationData +from common.environments.permissions import ( + MANAGE_SEGMENT_OVERRIDES, + UPDATE_FEATURE_STATE, + VIEW_ENVIRONMENT, +) from core.constants import FLAGSMITH_UPDATED_AT_HEADER from django.conf import settings from django.forms import model_to_dict @@ -27,11 +32,6 @@ from audit.models import AuditLog, RelatedObjectType from environments.identities.models import Identity from environments.models import Environment, EnvironmentAPIKey -from environments.permissions.constants import ( - MANAGE_SEGMENT_OVERRIDES, - UPDATE_FEATURE_STATE, - VIEW_ENVIRONMENT, -) from environments.permissions.models import UserEnvironmentPermission from features.feature_types import MULTIVARIATE from features.models import Feature, FeatureSegment, FeatureState diff --git a/api/tests/unit/features/versioning/test_unit_versioning_views.py b/api/tests/unit/features/versioning/test_unit_versioning_views.py index df30cbaf314f..85933b3f505c 100644 --- a/api/tests/unit/features/versioning/test_unit_versioning_views.py +++ b/api/tests/unit/features/versioning/test_unit_versioning_views.py @@ -3,6 +3,10 @@ from datetime import datetime, timedelta import pytest +from common.environments.permissions import ( + UPDATE_FEATURE_STATE, + VIEW_ENVIRONMENT, +) from core.constants import STRING from django.urls import reverse from django.utils import timezone @@ -15,10 +19,6 @@ from audit.models import AuditLog from audit.related_object_type import RelatedObjectType from environments.models import Environment -from environments.permissions.constants import ( - UPDATE_FEATURE_STATE, - VIEW_ENVIRONMENT, -) from features.feature_segments.limits import ( SEGMENT_OVERRIDE_LIMIT_EXCEEDED_MESSAGE, ) diff --git a/api/tests/unit/permissions/permission_service/test_get_permitted_environments_for_user.py b/api/tests/unit/permissions/permission_service/test_get_permitted_environments_for_user.py index 0383b98d7e98..6e2a5d442f50 100644 --- a/api/tests/unit/permissions/permission_service/test_get_permitted_environments_for_user.py +++ b/api/tests/unit/permissions/permission_service/test_get_permitted_environments_for_user.py @@ -1,11 +1,11 @@ import pytest -from pytest_lazyfixture import lazy_fixture - -from environments.permissions.constants import ( +from common.environments.permissions import ( MANAGE_IDENTITIES, UPDATE_FEATURE_STATE, VIEW_ENVIRONMENT, ) +from pytest_lazyfixture import lazy_fixture + from environments.permissions.models import EnvironmentPermissionModel from permissions.permission_service import get_permitted_environments_for_user diff --git a/api/tests/unit/permissions/test_unit_permissions_calculator.py b/api/tests/unit/permissions/test_unit_permissions_calculator.py index 76a240d6dfa7..20046c2115e8 100644 --- a/api/tests/unit/permissions/test_unit_permissions_calculator.py +++ b/api/tests/unit/permissions/test_unit_permissions_calculator.py @@ -1,9 +1,9 @@ import pytest - -from environments.permissions.constants import ( +from common.environments.permissions import ( UPDATE_FEATURE_STATE, VIEW_ENVIRONMENT, ) + from environments.permissions.models import ( EnvironmentPermissionModel, UserEnvironmentPermission, From 63edb3361c66a1414f5c18771c64f886f543270e Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 23 Oct 2024 15:51:21 +0000 Subject: [PATCH 112/122] Remove metadata serializers --- api/metadata/serializers.py | 70 ------------------------------------- 1 file changed, 70 deletions(-) diff --git a/api/metadata/serializers.py b/api/metadata/serializers.py index a6fdddf89582..be46aea7a8ce 100644 --- a/api/metadata/serializers.py +++ b/api/metadata/serializers.py @@ -1,15 +1,11 @@ from django.contrib.contenttypes.models import ContentType -from django.db.models import Model from rest_framework import serializers -from organisations.models import Organisation -from projects.models import Project from util.drf_writable_nested.serializers import ( DeleteBeforeUpdateWritableNestedModelSerializer, ) from .models import ( - Metadata, MetadataField, MetadataModelField, MetadataModelFieldRequirement, @@ -71,69 +67,3 @@ class ContentTypeSerializer(serializers.ModelSerializer): class Meta: model = ContentType fields = ("id", "app_label", "model") - - -class MetadataSerializer(serializers.ModelSerializer): - class Meta: - model = Metadata - fields = ("id", "model_field", "field_value") - - def validate(self, data): - data = super().validate(data) - if not data["model_field"].field.is_field_value_valid(data["field_value"]): - raise serializers.ValidationError( - f"Invalid value for field {data['model_field'].field.name}" - ) - - return data - - -class SerializerWithMetadata(serializers.BaseSerializer): - def get_organisation(self, validated_data: dict = None) -> Organisation: - return self.get_project(validated_data).organisation - - def get_project(self, validated_data: dict = None) -> Project: - raise NotImplementedError() - - def get_required_for_object( - self, requirement: MetadataModelFieldRequirement, data: dict - ) -> Model: - model_name = requirement.content_type.model - try: - return getattr(self, f"get_{model_name}")(data) - except AttributeError: - raise ValueError( - f"`get_{model_name}_from_validated_data` method does not exist" - ) - - def validate_required_metadata(self, data): - metadata = data.get("metadata", []) - - content_type = ContentType.objects.get_for_model(self.Meta.model) - - organisation = self.get_organisation(data) - - requirements = MetadataModelFieldRequirement.objects.filter( - model_field__content_type=content_type, - model_field__field__organisation=organisation, - ) - - for requirement in requirements: - required_for = self.get_required_for_object(requirement, data) - if required_for.id == requirement.object_id: - if not any( - [ - field["model_field"] == requirement.model_field - for field in metadata - ] - ): - raise serializers.ValidationError( - { - "metadata": f"Missing required metadata field: {requirement.model_field.field.name}" - } - ) - - def validate(self, data): - data = super().validate(data) - self.validate_required_metadata(data) - return data From 9df8694210962960db27b1906c362727de734fb7 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 23 Oct 2024 15:59:29 +0000 Subject: [PATCH 113/122] Update to common library for metadata serializers --- api/environments/serializers.py | 5 ++++- api/features/serializers.py | 5 ++++- api/segments/serializers.py | 5 ++++- api/tests/unit/metadata/test_serializers.py | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/api/environments/serializers.py b/api/environments/serializers.py index dffc9d13b468..de32b8bbacbb 100644 --- a/api/environments/serializers.py +++ b/api/environments/serializers.py @@ -1,10 +1,13 @@ import typing +from common.metadata.serializers import ( + MetadataSerializer, + SerializerWithMetadata, +) from rest_framework import serializers from environments.models import Environment, EnvironmentAPIKey, Webhook from features.serializers import FeatureStateSerializerFull -from metadata.serializers import MetadataSerializer, SerializerWithMetadata from organisations.models import Subscription from organisations.subscriptions.serializers.mixins import ( ReadOnlyIfNotValidPlanMixin, diff --git a/api/features/serializers.py b/api/features/serializers.py index f0226642d94c..2d57390660b7 100644 --- a/api/features/serializers.py +++ b/api/features/serializers.py @@ -9,6 +9,10 @@ CreateSegmentOverrideFeatureStateSerializer, FeatureStateValueSerializer, ) +from common.metadata.serializers import ( + MetadataSerializer, + SerializerWithMetadata, +) from drf_writable_nested import WritableNestedModelSerializer from drf_yasg.utils import swagger_serializer_method from rest_framework import serializers @@ -20,7 +24,6 @@ ) from integrations.github.constants import GitHubEventType from integrations.github.github import call_github_task -from metadata.serializers import MetadataSerializer, SerializerWithMetadata from projects.models import Project from users.serializers import ( UserIdsSerializer, diff --git a/api/segments/serializers.py b/api/segments/serializers.py index 861b701197fb..6b9e318c2917 100644 --- a/api/segments/serializers.py +++ b/api/segments/serializers.py @@ -1,6 +1,10 @@ import logging import typing +from common.metadata.serializers import ( + MetadataSerializer, + SerializerWithMetadata, +) from django.conf import settings from django.contrib.contenttypes.models import ContentType from flag_engine.segments.constants import PERCENTAGE_SPLIT @@ -10,7 +14,6 @@ from rest_framework_recursive.fields import RecursiveField from metadata.models import Metadata -from metadata.serializers import MetadataSerializer, SerializerWithMetadata from projects.models import Project from segments.models import Condition, Segment, SegmentRule diff --git a/api/tests/unit/metadata/test_serializers.py b/api/tests/unit/metadata/test_serializers.py index 3603288943bb..eb0ee7f4434c 100644 --- a/api/tests/unit/metadata/test_serializers.py +++ b/api/tests/unit/metadata/test_serializers.py @@ -1,11 +1,11 @@ import pytest +from common.metadata.serializers import MetadataSerializer from metadata.models import ( FIELD_VALUE_MAX_LENGTH, MetadataField, MetadataModelField, ) -from metadata.serializers import MetadataSerializer @pytest.mark.parametrize( From 6c2b2064314aae43e5351f0839539ae81b3bbe14 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 23 Oct 2024 18:41:40 +0000 Subject: [PATCH 114/122] Remove project permissions constants --- api/projects/permissions.py | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/api/projects/permissions.py b/api/projects/permissions.py index a5e3df160103..abd5c6f74de2 100644 --- a/api/projects/permissions.py +++ b/api/projects/permissions.py @@ -1,5 +1,6 @@ import typing +from common.projects.permissions import VIEW_PROJECT from django.db.models import Model from rest_framework.exceptions import APIException, PermissionDenied from rest_framework.permissions import BasePermission, IsAuthenticated @@ -8,42 +9,6 @@ from organisations.permissions.permissions import CREATE_PROJECT from projects.models import Project -VIEW_AUDIT_LOG = "VIEW_AUDIT_LOG" - -# Maintain a list of permissions here -VIEW_PROJECT = "VIEW_PROJECT" -CREATE_ENVIRONMENT = "CREATE_ENVIRONMENT" -DELETE_FEATURE = "DELETE_FEATURE" -CREATE_FEATURE = "CREATE_FEATURE" -EDIT_FEATURE = "EDIT_FEATURE" -MANAGE_SEGMENTS = "MANAGE_SEGMENTS" -MANAGE_TAGS = "MANAGE_TAGS" - -# Note that this does not impact change requests in an environment -MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS = "MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS" -APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS = "APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS" - -TAG_SUPPORTED_PERMISSIONS = [DELETE_FEATURE] - -PROJECT_PERMISSIONS = [ - (VIEW_PROJECT, "View permission for the given project."), - (CREATE_ENVIRONMENT, "Ability to create an environment in the given project."), - (DELETE_FEATURE, "Ability to delete features in the given project."), - (CREATE_FEATURE, "Ability to create features in the given project."), - (EDIT_FEATURE, "Ability to edit features in the given project."), - (MANAGE_SEGMENTS, "Ability to manage segments in the given project."), - (VIEW_AUDIT_LOG, "Allows the user to view the audit logs for this organisation."), - ( - MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS, - "Ability to manage change requests associated with a project.", - ), - ( - APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS, - "Ability to approve project level change requests.", - ), - (MANAGE_TAGS, "Allows the user to manage tags in the given project."), -] - class ProjectPermissions(IsAuthenticated): def has_permission(self, request, view): From dbea2b55ec7f95f47fd68a338f09fd88a60568f2 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 23 Oct 2024 19:10:35 +0000 Subject: [PATCH 115/122] Update to common library for project permissions constants --- api/audit/permissions.py | 2 +- api/conftest.py | 2 +- api/e2etests/e2e_seed_data.py | 410 +++++++++--------- api/environments/permissions/permissions.py | 2 +- api/features/feature_segments/views.py | 2 +- api/features/import_export/permissions.py | 2 +- api/features/multivariate/views.py | 7 +- api/features/permissions.py | 10 +- api/features/versioning/views.py | 2 +- api/features/views.py | 2 +- api/integrations/common/views.py | 3 +- api/integrations/launch_darkly/views.py | 7 +- api/permissions/migrations/0001_initial.py | 2 +- .../0008_add_view_audit_log_permission.py | 2 +- .../0009_move_view_audit_log_permission.py | 13 +- .../0010_add_manage_tags_permission.py | 10 +- .../migrations/0003_auto_20200216_2050.py | 18 +- ..._add_change_request_project_permissions.py | 8 +- api/projects/tags/permissions.py | 2 +- api/projects/tags/views.py | 3 +- api/projects/views.py | 7 +- api/segments/permissions.py | 2 +- api/segments/views.py | 2 +- api/tests/unit/audit/conftest.py | 2 +- api/tests/unit/environments/helpers.py | 2 +- .../identities/traits/test_traits_views.py | 2 +- .../test_unit_environments_permissions.py | 3 +- .../test_unit_environments_views.py | 2 +- .../test_unit_feature_segments_views.py | 2 +- .../test_unit_features_import_export_views.py | 2 +- .../test_unit_multivariate_views.py | 7 +- .../test_unit_features_permissions.py | 12 +- .../unit/features/test_unit_features_views.py | 2 +- .../versioning/test_unit_versioning_views.py | 2 +- .../test_get_permitted_projects_for_user.py | 10 +- .../test_unit_permissions_calculator.py | 2 +- .../test_unit_projects_tags_permissions.py | 3 +- .../tags/test_unit_projects_tags_views.py | 2 +- api/tests/unit/projects/test_migrations.py | 3 +- .../test_unit_projects_permissions.py | 7 +- .../unit/projects/test_unit_projects_views.py | 10 +- .../test_unit_segments_permissions.py | 3 +- .../unit/segments/test_unit_segments_views.py | 2 +- .../unit/users/test_unit_users_models.py | 2 +- 44 files changed, 300 insertions(+), 302 deletions(-) diff --git a/api/audit/permissions.py b/api/audit/permissions.py index 6695ac696fec..b8b0ae3b48e7 100644 --- a/api/audit/permissions.py +++ b/api/audit/permissions.py @@ -1,10 +1,10 @@ +from common.projects.permissions import VIEW_AUDIT_LOG from django.views import View from rest_framework.permissions import BasePermission from rest_framework.request import Request from organisations.models import Organisation from projects.models import Project -from projects.permissions import VIEW_AUDIT_LOG class OrganisationAuditLogPermissions(BasePermission): diff --git a/api/conftest.py b/api/conftest.py index 22691cd4619f..f1803f196db0 100644 --- a/api/conftest.py +++ b/api/conftest.py @@ -10,6 +10,7 @@ VIEW_ENVIRONMENT, VIEW_IDENTITIES, ) +from common.projects.permissions import VIEW_PROJECT from django.contrib.contenttypes.models import ContentType from django.core.cache import caches from django.db.backends.base.creation import TEST_DATABASE_PREFIX @@ -66,7 +67,6 @@ UserPermissionGroupProjectPermission, UserProjectPermission, ) -from projects.permissions import VIEW_PROJECT from projects.tags.models import Tag from segments.models import Condition, Segment, SegmentRule from tests.test_helpers import fix_issue_3869 diff --git a/api/e2etests/e2e_seed_data.py b/api/e2etests/e2e_seed_data.py index 6a60527abf80..592b4a6de490 100644 --- a/api/e2etests/e2e_seed_data.py +++ b/api/e2etests/e2e_seed_data.py @@ -1,205 +1,205 @@ -from common.environments.permissions import ( - UPDATE_FEATURE_STATE, - VIEW_ENVIRONMENT, - VIEW_IDENTITIES, -) -from django.conf import settings -from flag_engine.identities.models import IdentityModel as EngineIdentity - -from edge_api.identities.models import EdgeIdentity -from environments.identities.models import Identity -from environments.models import Environment -from environments.permissions.models import UserEnvironmentPermission -from organisations.models import Organisation, OrganisationRole, Subscription -from organisations.permissions.models import UserOrganisationPermission -from organisations.permissions.permissions import ( - CREATE_PROJECT, - MANAGE_USER_GROUPS, -) -from organisations.subscriptions.constants import SCALE_UP -from projects.models import Project, UserProjectPermission -from projects.permissions import ( - CREATE_ENVIRONMENT, - CREATE_FEATURE, - VIEW_AUDIT_LOG, - VIEW_PROJECT, -) -from users.models import FFAdminUser, UserPermissionGroup - -# Password used by all the test users -PASSWORD = "Str0ngp4ssw0rd!" - -PROJECT_PERMISSION_PROJECT = "My Test Project 5 Project Permission" -ENV_PERMISSION_PROJECT = "My Test Project 6 Env Permission" - - -def delete_user_and_its_organisations(user_email: str) -> None: - user: FFAdminUser | None = FFAdminUser.objects.filter(email=user_email).first() - - if user: - user.organisations.all().delete() - user.delete() - - -def teardown() -> None: - # delete users and their orgs created for e2e test by front end - delete_user_and_its_organisations(user_email=settings.E2E_SIGNUP_USER) - delete_user_and_its_organisations(user_email=settings.E2E_USER) - delete_user_and_its_organisations(user_email=settings.E2E_CHANGE_EMAIL_USER) - delete_user_and_its_organisations( - user_email=settings.E2E_NON_ADMIN_USER_WITH_ORG_PERMISSIONS - ) - delete_user_and_its_organisations( - user_email=settings.E2E_NON_ADMIN_USER_WITH_PROJECT_PERMISSIONS - ) - delete_user_and_its_organisations( - user_email=settings.E2E_NON_ADMIN_USER_WITH_ENV_PERMISSIONS - ) - delete_user_and_its_organisations( - user_email=settings.E2E_NON_ADMIN_USER_WITH_A_ROLE - ) - - -def seed_data() -> None: - # create user and organisation for e2e test by front end - organisation: Organisation = Organisation.objects.create(name="Bullet Train Ltd") - org_admin: FFAdminUser = FFAdminUser.objects.create_user( - email=settings.E2E_USER, - password=PASSWORD, - username=settings.E2E_USER, - ) - org_admin.add_organisation(organisation, OrganisationRole.ADMIN) - non_admin_user_with_org_permissions: FFAdminUser = FFAdminUser.objects.create_user( - email=settings.E2E_NON_ADMIN_USER_WITH_ORG_PERMISSIONS, - password=PASSWORD, - ) - non_admin_user_with_project_permissions: FFAdminUser = ( - FFAdminUser.objects.create_user( - email=settings.E2E_NON_ADMIN_USER_WITH_PROJECT_PERMISSIONS, - password=PASSWORD, - ) - ) - non_admin_user_with_env_permissions: FFAdminUser = FFAdminUser.objects.create_user( - email=settings.E2E_NON_ADMIN_USER_WITH_ENV_PERMISSIONS, - password=PASSWORD, - ) - non_admin_user_with_a_role: FFAdminUser = FFAdminUser.objects.create_user( - email=settings.E2E_NON_ADMIN_USER_WITH_A_ROLE, - password=PASSWORD, - ) - non_admin_user_with_org_permissions.add_organisation( - organisation, - ) - non_admin_user_with_project_permissions.add_organisation( - organisation, - ) - non_admin_user_with_env_permissions.add_organisation( - organisation, - ) - non_admin_user_with_a_role.add_organisation( - organisation, - ) - - # Add permissions to the non-admin user with org permissions - user_org_permission = UserOrganisationPermission.objects.create( - user=non_admin_user_with_org_permissions, organisation=organisation - ) - user_org_permission.add_permission(CREATE_PROJECT) - user_org_permission.add_permission(MANAGE_USER_GROUPS) - UserPermissionGroup.objects.create(name="TestGroup", organisation=organisation) - - # We add different projects and environments to give each e2e test its own isolated context. - project_test_data = [ - { - "name": "My Test Project", - "environments": [ - "Development", - "Production", - ], - }, - {"name": "My Test Project 2", "environments": ["Development"]}, - {"name": "My Test Project 3", "environments": ["Development"]}, - {"name": "My Test Project 4", "environments": ["Development"]}, - { - "name": PROJECT_PERMISSION_PROJECT, - "environments": ["Development"], - }, - {"name": ENV_PERMISSION_PROJECT, "environments": ["Development"]}, - {"name": "My Test Project 7 Role", "environments": ["Development"]}, - ] - # Upgrade organisation seats - Subscription.objects.filter(organisation__in=org_admin.organisations.all()).update( - max_seats=8, plan=SCALE_UP, subscription_id="test_subscription_id" - ) - - # Create projects and environments - projects = [] - environments = [] - for project_info in project_test_data: - project = Project.objects.create( - name=project_info["name"], organisation=organisation - ) - if project_info["name"] == PROJECT_PERMISSION_PROJECT: - # Add permissions to the non-admin user with project permissions - user_proj_permission: UserProjectPermission = ( - UserProjectPermission.objects.create( - user=non_admin_user_with_project_permissions, project=project - ) - ) - [ - user_proj_permission.add_permission(permission_key) - for permission_key in [ - VIEW_PROJECT, - CREATE_ENVIRONMENT, - CREATE_FEATURE, - VIEW_AUDIT_LOG, - ] - ] - projects.append(project) - - for env_name in project_info["environments"]: - environment = Environment.objects.create(name=env_name, project=project) - - if project_info["name"] == ENV_PERMISSION_PROJECT: - # Add permissions to the non-admin user with env permissions - user_env_permission = UserEnvironmentPermission.objects.create( - user=non_admin_user_with_env_permissions, environment=environment - ) - user_env_proj_permission: UserProjectPermission = ( - UserProjectPermission.objects.create( - user=non_admin_user_with_env_permissions, project=project - ) - ) - user_env_proj_permission.add_permission(VIEW_PROJECT) - user_env_proj_permission.add_permission(CREATE_FEATURE) - [ - user_env_permission.add_permission(permission_key) - for permission_key in [ - VIEW_ENVIRONMENT, - UPDATE_FEATURE_STATE, - VIEW_IDENTITIES, - ] - ] - environments.append(environment) - - # We're only creating identities for 6 of the 7 environments because - # they are necessary for the environments created above and to keep - # the e2e tests isolated." - identities_test_data = [ - {"identifier": settings.E2E_IDENTITY, "environment": environments[2]}, - {"identifier": settings.E2E_IDENTITY, "environment": environments[3]}, - {"identifier": settings.E2E_IDENTITY, "environment": environments[4]}, - {"identifier": settings.E2E_IDENTITY, "environment": environments[5]}, - {"identifier": settings.E2E_IDENTITY, "environment": environments[6]}, - {"identifier": settings.E2E_IDENTITY, "environment": environments[7]}, - ] - - for identity_info in identities_test_data: - if settings.IDENTITIES_TABLE_NAME_DYNAMO: - engine_identity = EngineIdentity( - identifier=identity_info["identifier"], - environment_api_key=identity_info["environment"].api_key, - ) - EdgeIdentity(engine_identity).save() - else: - Identity.objects.create(**identity_info) +from common.environments.permissions import ( + UPDATE_FEATURE_STATE, + VIEW_ENVIRONMENT, + VIEW_IDENTITIES, +) +from common.projects.permissions import ( + CREATE_ENVIRONMENT, + CREATE_FEATURE, + VIEW_AUDIT_LOG, + VIEW_PROJECT, +) +from django.conf import settings +from flag_engine.identities.models import IdentityModel as EngineIdentity + +from edge_api.identities.models import EdgeIdentity +from environments.identities.models import Identity +from environments.models import Environment +from environments.permissions.models import UserEnvironmentPermission +from organisations.models import Organisation, OrganisationRole, Subscription +from organisations.permissions.models import UserOrganisationPermission +from organisations.permissions.permissions import ( + CREATE_PROJECT, + MANAGE_USER_GROUPS, +) +from organisations.subscriptions.constants import SCALE_UP +from projects.models import Project, UserProjectPermission +from users.models import FFAdminUser, UserPermissionGroup + +# Password used by all the test users +PASSWORD = "Str0ngp4ssw0rd!" + +PROJECT_PERMISSION_PROJECT = "My Test Project 5 Project Permission" +ENV_PERMISSION_PROJECT = "My Test Project 6 Env Permission" + + +def delete_user_and_its_organisations(user_email: str) -> None: + user: FFAdminUser | None = FFAdminUser.objects.filter(email=user_email).first() + + if user: + user.organisations.all().delete() + user.delete() + + +def teardown() -> None: + # delete users and their orgs created for e2e test by front end + delete_user_and_its_organisations(user_email=settings.E2E_SIGNUP_USER) + delete_user_and_its_organisations(user_email=settings.E2E_USER) + delete_user_and_its_organisations(user_email=settings.E2E_CHANGE_EMAIL_USER) + delete_user_and_its_organisations( + user_email=settings.E2E_NON_ADMIN_USER_WITH_ORG_PERMISSIONS + ) + delete_user_and_its_organisations( + user_email=settings.E2E_NON_ADMIN_USER_WITH_PROJECT_PERMISSIONS + ) + delete_user_and_its_organisations( + user_email=settings.E2E_NON_ADMIN_USER_WITH_ENV_PERMISSIONS + ) + delete_user_and_its_organisations( + user_email=settings.E2E_NON_ADMIN_USER_WITH_A_ROLE + ) + + +def seed_data() -> None: + # create user and organisation for e2e test by front end + organisation: Organisation = Organisation.objects.create(name="Bullet Train Ltd") + org_admin: FFAdminUser = FFAdminUser.objects.create_user( + email=settings.E2E_USER, + password=PASSWORD, + username=settings.E2E_USER, + ) + org_admin.add_organisation(organisation, OrganisationRole.ADMIN) + non_admin_user_with_org_permissions: FFAdminUser = FFAdminUser.objects.create_user( + email=settings.E2E_NON_ADMIN_USER_WITH_ORG_PERMISSIONS, + password=PASSWORD, + ) + non_admin_user_with_project_permissions: FFAdminUser = ( + FFAdminUser.objects.create_user( + email=settings.E2E_NON_ADMIN_USER_WITH_PROJECT_PERMISSIONS, + password=PASSWORD, + ) + ) + non_admin_user_with_env_permissions: FFAdminUser = FFAdminUser.objects.create_user( + email=settings.E2E_NON_ADMIN_USER_WITH_ENV_PERMISSIONS, + password=PASSWORD, + ) + non_admin_user_with_a_role: FFAdminUser = FFAdminUser.objects.create_user( + email=settings.E2E_NON_ADMIN_USER_WITH_A_ROLE, + password=PASSWORD, + ) + non_admin_user_with_org_permissions.add_organisation( + organisation, + ) + non_admin_user_with_project_permissions.add_organisation( + organisation, + ) + non_admin_user_with_env_permissions.add_organisation( + organisation, + ) + non_admin_user_with_a_role.add_organisation( + organisation, + ) + + # Add permissions to the non-admin user with org permissions + user_org_permission = UserOrganisationPermission.objects.create( + user=non_admin_user_with_org_permissions, organisation=organisation + ) + user_org_permission.add_permission(CREATE_PROJECT) + user_org_permission.add_permission(MANAGE_USER_GROUPS) + UserPermissionGroup.objects.create(name="TestGroup", organisation=organisation) + + # We add different projects and environments to give each e2e test its own isolated context. + project_test_data = [ + { + "name": "My Test Project", + "environments": [ + "Development", + "Production", + ], + }, + {"name": "My Test Project 2", "environments": ["Development"]}, + {"name": "My Test Project 3", "environments": ["Development"]}, + {"name": "My Test Project 4", "environments": ["Development"]}, + { + "name": PROJECT_PERMISSION_PROJECT, + "environments": ["Development"], + }, + {"name": ENV_PERMISSION_PROJECT, "environments": ["Development"]}, + {"name": "My Test Project 7 Role", "environments": ["Development"]}, + ] + # Upgrade organisation seats + Subscription.objects.filter(organisation__in=org_admin.organisations.all()).update( + max_seats=8, plan=SCALE_UP, subscription_id="test_subscription_id" + ) + + # Create projects and environments + projects = [] + environments = [] + for project_info in project_test_data: + project = Project.objects.create( + name=project_info["name"], organisation=organisation + ) + if project_info["name"] == PROJECT_PERMISSION_PROJECT: + # Add permissions to the non-admin user with project permissions + user_proj_permission: UserProjectPermission = ( + UserProjectPermission.objects.create( + user=non_admin_user_with_project_permissions, project=project + ) + ) + [ + user_proj_permission.add_permission(permission_key) + for permission_key in [ + VIEW_PROJECT, + CREATE_ENVIRONMENT, + CREATE_FEATURE, + VIEW_AUDIT_LOG, + ] + ] + projects.append(project) + + for env_name in project_info["environments"]: + environment = Environment.objects.create(name=env_name, project=project) + + if project_info["name"] == ENV_PERMISSION_PROJECT: + # Add permissions to the non-admin user with env permissions + user_env_permission = UserEnvironmentPermission.objects.create( + user=non_admin_user_with_env_permissions, environment=environment + ) + user_env_proj_permission: UserProjectPermission = ( + UserProjectPermission.objects.create( + user=non_admin_user_with_env_permissions, project=project + ) + ) + user_env_proj_permission.add_permission(VIEW_PROJECT) + user_env_proj_permission.add_permission(CREATE_FEATURE) + [ + user_env_permission.add_permission(permission_key) + for permission_key in [ + VIEW_ENVIRONMENT, + UPDATE_FEATURE_STATE, + VIEW_IDENTITIES, + ] + ] + environments.append(environment) + + # We're only creating identities for 6 of the 7 environments because + # they are necessary for the environments created above and to keep + # the e2e tests isolated." + identities_test_data = [ + {"identifier": settings.E2E_IDENTITY, "environment": environments[2]}, + {"identifier": settings.E2E_IDENTITY, "environment": environments[3]}, + {"identifier": settings.E2E_IDENTITY, "environment": environments[4]}, + {"identifier": settings.E2E_IDENTITY, "environment": environments[5]}, + {"identifier": settings.E2E_IDENTITY, "environment": environments[6]}, + {"identifier": settings.E2E_IDENTITY, "environment": environments[7]}, + ] + + for identity_info in identities_test_data: + if settings.IDENTITIES_TABLE_NAME_DYNAMO: + engine_identity = EngineIdentity( + identifier=identity_info["identifier"], + environment_api_key=identity_info["environment"].api_key, + ) + EdgeIdentity(engine_identity).save() + else: + Identity.objects.create(**identity_info) diff --git a/api/environments/permissions/permissions.py b/api/environments/permissions/permissions.py index 7a4acc4fcb47..20dae8704818 100644 --- a/api/environments/permissions/permissions.py +++ b/api/environments/permissions/permissions.py @@ -1,13 +1,13 @@ import typing from common.environments.permissions import VIEW_ENVIRONMENT +from common.projects.permissions import CREATE_ENVIRONMENT from django.db.models import Model, Q from rest_framework import exceptions from rest_framework.permissions import BasePermission, IsAuthenticated from environments.models import Environment from projects.models import Project -from projects.permissions import CREATE_ENVIRONMENT class EnvironmentKeyPermissions(BasePermission): diff --git a/api/features/feature_segments/views.py b/api/features/feature_segments/views.py index 691c916fff16..320ad2a298ae 100644 --- a/api/features/feature_segments/views.py +++ b/api/features/feature_segments/views.py @@ -1,5 +1,6 @@ import logging +from common.projects.permissions import VIEW_PROJECT from django.utils.decorators import method_decorator from drf_yasg.utils import swagger_auto_schema from rest_framework import viewsets @@ -18,7 +19,6 @@ from features.versioning.versioning_service import ( get_current_live_environment_feature_version, ) -from projects.permissions import VIEW_PROJECT from .permissions import FeatureSegmentPermissions diff --git a/api/features/import_export/permissions.py b/api/features/import_export/permissions.py index 8325e5d1c15e..ce20e525e72a 100644 --- a/api/features/import_export/permissions.py +++ b/api/features/import_export/permissions.py @@ -1,3 +1,4 @@ +from common.projects.permissions import VIEW_PROJECT from rest_framework.generics import ListAPIView from rest_framework.permissions import IsAuthenticated from rest_framework.request import Request @@ -5,7 +6,6 @@ from environments.models import Environment from features.import_export.models import FeatureExport from projects.models import Project -from projects.permissions import VIEW_PROJECT class FeatureImportPermissions(IsAuthenticated): diff --git a/api/features/multivariate/views.py b/api/features/multivariate/views.py index 4f115d7634a6..9bd08fc036cb 100644 --- a/api/features/multivariate/views.py +++ b/api/features/multivariate/views.py @@ -1,3 +1,4 @@ +from common.projects.permissions import CREATE_FEATURE, VIEW_PROJECT from drf_yasg.utils import swagger_auto_schema from rest_framework import viewsets from rest_framework.decorators import api_view @@ -5,11 +6,7 @@ from rest_framework.response import Response from features.models import Feature -from projects.permissions import ( - CREATE_FEATURE, - VIEW_PROJECT, - NestedProjectPermissions, -) +from projects.permissions import NestedProjectPermissions from .models import MultivariateFeatureOption from .serializers import MultivariateFeatureOptionSerializer diff --git a/api/features/permissions.py b/api/features/permissions.py index b1deb32a42f2..15f471d06829 100644 --- a/api/features/permissions.py +++ b/api/features/permissions.py @@ -8,6 +8,11 @@ UPDATE_FEATURE_STATE, VIEW_ENVIRONMENT, ) +from common.projects.permissions import CREATE_FEATURE, DELETE_FEATURE +from common.projects.permissions import ( + TAG_SUPPORTED_PERMISSIONS as TAG_SUPPORTED_PROJECT_PERMISSIONS, +) +from common.projects.permissions import VIEW_PROJECT from django.shortcuts import get_object_or_404 from rest_framework.permissions import IsAuthenticated from rest_framework.request import Request @@ -16,11 +21,6 @@ from environments.models import Environment from features.models import Feature, FeatureState from projects.models import Project -from projects.permissions import CREATE_FEATURE, DELETE_FEATURE -from projects.permissions import ( - TAG_SUPPORTED_PERMISSIONS as TAG_SUPPORTED_PROJECT_PERMISSIONS, -) -from projects.permissions import VIEW_PROJECT ACTION_PERMISSIONS_MAP = { "retrieve": VIEW_PROJECT, diff --git a/api/features/versioning/views.py b/api/features/versioning/views.py index 07840a23bb79..ba62725dda5c 100644 --- a/api/features/versioning/views.py +++ b/api/features/versioning/views.py @@ -1,4 +1,5 @@ from common.environments.permissions import VIEW_ENVIRONMENT +from common.projects.permissions import VIEW_PROJECT from django.db.models import BooleanField, ExpressionWrapper, Q from django.shortcuts import get_object_or_404 from django.utils import timezone @@ -38,7 +39,6 @@ EnvironmentFeatureVersionRetrieveSerializer, EnvironmentFeatureVersionSerializer, ) -from projects.permissions import VIEW_PROJECT from users.models import FFAdminUser diff --git a/api/features/views.py b/api/features/views.py index b62973aceca1..c12084565f38 100644 --- a/api/features/views.py +++ b/api/features/views.py @@ -5,6 +5,7 @@ from app_analytics.analytics_db_service import get_feature_evaluation_data from app_analytics.influxdb_wrapper import get_multiple_event_list_for_feature +from common.projects.permissions import VIEW_PROJECT from core.constants import FLAGSMITH_UPDATED_AT_HEADER from core.request_origin import RequestOrigin from django.conf import settings @@ -38,7 +39,6 @@ ) from features.value_types import BOOLEAN, INTEGER, STRING from projects.models import Project -from projects.permissions import VIEW_PROJECT from users.models import FFAdminUser, UserPermissionGroup from webhooks.webhooks import WebhookEventType diff --git a/api/integrations/common/views.py b/api/integrations/common/views.py index 19b4b8765742..64a37f91f352 100644 --- a/api/integrations/common/views.py +++ b/api/integrations/common/views.py @@ -1,4 +1,5 @@ from common.environments.permissions import VIEW_ENVIRONMENT +from common.projects.permissions import VIEW_PROJECT from django.db.models import QuerySet from django.shortcuts import get_object_or_404 from rest_framework import viewsets @@ -12,7 +13,7 @@ from organisations.permissions.permissions import ( NestedOrganisationEntityPermission, ) -from projects.permissions import VIEW_PROJECT, NestedProjectPermissions +from projects.permissions import NestedProjectPermissions class EnvironmentIntegrationCommonViewSet(viewsets.ModelViewSet): diff --git a/api/integrations/launch_darkly/views.py b/api/integrations/launch_darkly/views.py index 93e2ddc0cc81..a781d416a8e5 100644 --- a/api/integrations/launch_darkly/views.py +++ b/api/integrations/launch_darkly/views.py @@ -1,3 +1,4 @@ +from common.projects.permissions import CREATE_ENVIRONMENT, VIEW_PROJECT from django.db.models import QuerySet from django.db.utils import IntegrityError from django.shortcuts import get_object_or_404 @@ -18,11 +19,7 @@ process_launch_darkly_import_request, ) from projects.models import Project -from projects.permissions import ( - CREATE_ENVIRONMENT, - VIEW_PROJECT, - NestedProjectPermissions, -) +from projects.permissions import NestedProjectPermissions class LaunchDarklyImportRequestViewSet( diff --git a/api/permissions/migrations/0001_initial.py b/api/permissions/migrations/0001_initial.py index e78d60227786..5c2e4a57233b 100644 --- a/api/permissions/migrations/0001_initial.py +++ b/api/permissions/migrations/0001_initial.py @@ -7,13 +7,13 @@ UPDATE_FEATURE_STATE, VIEW_ENVIRONMENT, ) +from common.projects.permissions import PROJECT_PERMISSIONS from django.db import migrations, models from permissions.models import ( ENVIRONMENT_PERMISSION_TYPE, PROJECT_PERMISSION_TYPE, ) -from projects.permissions import PROJECT_PERMISSIONS ENVIRONMENT_PERMISSIONS = [ (VIEW_ENVIRONMENT, "View permission for the given environment."), diff --git a/api/permissions/migrations/0008_add_view_audit_log_permission.py b/api/permissions/migrations/0008_add_view_audit_log_permission.py index 3e1b351602c1..fb4e2a712f11 100644 --- a/api/permissions/migrations/0008_add_view_audit_log_permission.py +++ b/api/permissions/migrations/0008_add_view_audit_log_permission.py @@ -1,10 +1,10 @@ # Generated by Django 3.2.16 on 2022-12-08 11:02 +from common.projects.permissions import VIEW_AUDIT_LOG from django.apps.registry import Apps from django.db import migrations from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from projects.permissions import VIEW_AUDIT_LOG from permissions.models import ORGANISATION_PERMISSION_TYPE diff --git a/api/permissions/migrations/0009_move_view_audit_log_permission.py b/api/permissions/migrations/0009_move_view_audit_log_permission.py index b3c03233867d..e11762440d37 100644 --- a/api/permissions/migrations/0009_move_view_audit_log_permission.py +++ b/api/permissions/migrations/0009_move_view_audit_log_permission.py @@ -1,16 +1,17 @@ # Generated by Django 3.2.16 on 2022-12-08 11:02 +from common.projects.permissions import VIEW_AUDIT_LOG from django.apps.registry import Apps from django.db import migrations from django.db.backends.base.schema import BaseDatabaseSchemaEditor -from projects.permissions import VIEW_AUDIT_LOG -from permissions.models import ORGANISATION_PERMISSION_TYPE, PROJECT_PERMISSION_TYPE +from permissions.models import ( + ORGANISATION_PERMISSION_TYPE, + PROJECT_PERMISSION_TYPE, +) -def move_permission_to_project( - apps: Apps, schema_editor: BaseDatabaseSchemaEditor -): +def move_permission_to_project(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): permission_model_class = apps.get_model("permissions", "PermissionModel") permission_model_class.objects.filter( @@ -43,4 +44,4 @@ class Migration(migrations.Migration): migrations.RunPython( move_permission_to_project, reverse_code=move_permission_to_organisation ) - ] \ No newline at end of file + ] diff --git a/api/permissions/migrations/0010_add_manage_tags_permission.py b/api/permissions/migrations/0010_add_manage_tags_permission.py index c7ddfd24e538..7e10801b6bde 100644 --- a/api/permissions/migrations/0010_add_manage_tags_permission.py +++ b/api/permissions/migrations/0010_add_manage_tags_permission.py @@ -1,13 +1,15 @@ # Generated by Django 4.2.15 on 2024-09-13 16:18 +from common.projects.permissions import MANAGE_TAGS from django.apps.registry import Apps from django.db import migrations from django.db.backends.base.schema import BaseDatabaseSchemaEditor from permissions.models import PROJECT_PERMISSION_TYPE -from projects.permissions import MANAGE_TAGS -def add_manage_tags_permission(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) -> None: +def add_manage_tags_permission( + apps: Apps, schema_editor: BaseDatabaseSchemaEditor +) -> None: permission_model_class = apps.get_model("permissions", "permissionmodel") permission_model_class.objects.get_or_create( key=MANAGE_TAGS, @@ -16,7 +18,9 @@ def add_manage_tags_permission(apps: Apps, schema_editor: BaseDatabaseSchemaEdit ) -def reverse(apps: Apps, schema_editor: BaseDatabaseSchemaEditor) -> None: # pragma: no cover +def reverse( + apps: Apps, schema_editor: BaseDatabaseSchemaEditor +) -> None: # pragma: no cover permission_model_class = apps.get_model("permissions", "permissionmodel") permission_model_class.objects.filter(key=MANAGE_TAGS).delete() diff --git a/api/projects/migrations/0003_auto_20200216_2050.py b/api/projects/migrations/0003_auto_20200216_2050.py index 21e8b7ea115d..eb61d86910b7 100644 --- a/api/projects/migrations/0003_auto_20200216_2050.py +++ b/api/projects/migrations/0003_auto_20200216_2050.py @@ -1,16 +1,17 @@ # Generated by Django 2.2.10 on 2020-02-16 20:50 +from common.projects.permissions import PROJECT_PERMISSIONS from django.db import migrations -from projects.permissions import PROJECT_PERMISSIONS - def insert_default_permissions(apps, schema_model): - ProjectPermission = apps.get_model('projects', 'ProjectPermission') + ProjectPermission = apps.get_model("projects", "ProjectPermission") project_permissions = [] for permission in PROJECT_PERMISSIONS: - project_permissions.append(ProjectPermission(key=permission[0], description=permission[1])) + project_permissions.append( + ProjectPermission(key=permission[0], description=permission[1]) + ) ProjectPermission.objects.bulk_create(project_permissions) @@ -18,9 +19,14 @@ def insert_default_permissions(apps, schema_model): class Migration(migrations.Migration): dependencies = [ - ('projects', '0002_projectpermission_userpermissiongroupprojectpermission_userprojectpermission'), + ( + "projects", + "0002_projectpermission_userpermissiongroupprojectpermission_userprojectpermission", + ), ] operations = [ - migrations.RunPython(insert_default_permissions, reverse_code=lambda *args: None) + migrations.RunPython( + insert_default_permissions, reverse_code=lambda *args: None + ) ] diff --git a/api/projects/migrations/0025_add_change_request_project_permissions.py b/api/projects/migrations/0025_add_change_request_project_permissions.py index 673be8cc4674..336c209eeb82 100644 --- a/api/projects/migrations/0025_add_change_request_project_permissions.py +++ b/api/projects/migrations/0025_add_change_request_project_permissions.py @@ -1,13 +1,13 @@ # Generated by Django 4.2.15 on 2024-09-17 14:07 -from django.db import migrations - -from permissions.models import PROJECT_PERMISSION_TYPE -from projects.permissions import ( +from common.projects.permissions import ( APPROVE_PROJECT_LEVEL_CHANGE_REQUESTS, MANAGE_PROJECT_LEVEL_CHANGE_REQUESTS, PROJECT_PERMISSIONS, ) +from django.db import migrations + +from permissions.models import PROJECT_PERMISSION_TYPE def remove_default_project_permissions(apps, schema_model): # pragma: no cover diff --git a/api/projects/tags/permissions.py b/api/projects/tags/permissions.py index 88a480624952..41c7f2d9dfec 100644 --- a/api/projects/tags/permissions.py +++ b/api/projects/tags/permissions.py @@ -1,7 +1,7 @@ +from common.projects.permissions import MANAGE_TAGS, VIEW_PROJECT from rest_framework.permissions import BasePermission from projects.models import Project -from projects.permissions import MANAGE_TAGS, VIEW_PROJECT class TagPermissions(BasePermission): diff --git a/api/projects/tags/views.py b/api/projects/tags/views.py index 49b163316240..bd0a07a73217 100644 --- a/api/projects/tags/views.py +++ b/api/projects/tags/views.py @@ -1,3 +1,4 @@ +from common.projects.permissions import VIEW_PROJECT from rest_framework import status, viewsets from rest_framework.decorators import action from rest_framework.generics import get_object_or_404 @@ -5,8 +6,6 @@ from rest_framework.request import Request from rest_framework.response import Response -from projects.permissions import VIEW_PROJECT - from . import serializers from .models import Tag from .permissions import TagPermissions diff --git a/api/projects/views.py b/api/projects/views.py index 6d2b2f82e260..d81a2af2b43c 100644 --- a/api/projects/views.py +++ b/api/projects/views.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +from common.projects.permissions import VIEW_PROJECT from django.conf import settings from django.utils.decorators import method_decorator from drf_yasg import openapi @@ -33,11 +34,7 @@ UserPermissionGroupProjectPermission, UserProjectPermission, ) -from projects.permissions import ( - VIEW_PROJECT, - IsProjectAdmin, - ProjectPermissions, -) +from projects.permissions import IsProjectAdmin, ProjectPermissions from projects.serializers import ( CreateUpdateUserPermissionGroupProjectPermissionSerializer, CreateUpdateUserProjectPermissionSerializer, diff --git a/api/segments/permissions.py b/api/segments/permissions.py index efb901bc0177..283acec53596 100644 --- a/api/segments/permissions.py +++ b/api/segments/permissions.py @@ -1,7 +1,7 @@ +from common.projects.permissions import MANAGE_SEGMENTS, VIEW_PROJECT from rest_framework.permissions import IsAuthenticated from projects.models import Project -from projects.permissions import MANAGE_SEGMENTS, VIEW_PROJECT class SegmentPermissions(IsAuthenticated): diff --git a/api/segments/views.py b/api/segments/views.py index c1426195aba0..363bada84fab 100644 --- a/api/segments/views.py +++ b/api/segments/views.py @@ -1,5 +1,6 @@ import logging +from common.projects.permissions import VIEW_PROJECT from django.utils.decorators import method_decorator from drf_yasg.utils import swagger_auto_schema from rest_framework import viewsets @@ -12,7 +13,6 @@ from environments.identities.models import Identity from features.models import FeatureState from features.serializers import SegmentAssociatedFeatureStateSerializer -from projects.permissions import VIEW_PROJECT from .models import Segment from .permissions import SegmentPermissions diff --git a/api/tests/unit/audit/conftest.py b/api/tests/unit/audit/conftest.py index 93b0741394a4..605341072cc4 100644 --- a/api/tests/unit/audit/conftest.py +++ b/api/tests/unit/audit/conftest.py @@ -1,12 +1,12 @@ import typing import pytest as pytest +from common.projects.permissions import VIEW_AUDIT_LOG from django.db.models import Model from organisations.models import OrganisationRole from permissions.models import PermissionModel from projects.models import Project, UserProjectPermission -from projects.permissions import VIEW_AUDIT_LOG @pytest.fixture() diff --git a/api/tests/unit/environments/helpers.py b/api/tests/unit/environments/helpers.py index bf55c8ffab51..c6e89569c79b 100644 --- a/api/tests/unit/environments/helpers.py +++ b/api/tests/unit/environments/helpers.py @@ -1,5 +1,6 @@ import typing +from common.projects.permissions import VIEW_PROJECT from rest_framework.test import APIClient from environments.models import Environment @@ -8,7 +9,6 @@ UserEnvironmentPermission, ) from projects.models import ProjectPermissionModel, UserProjectPermission -from projects.permissions import VIEW_PROJECT from users.models import FFAdminUser diff --git a/api/tests/unit/environments/identities/traits/test_traits_views.py b/api/tests/unit/environments/identities/traits/test_traits_views.py index f52c09e09b38..61831fe93871 100644 --- a/api/tests/unit/environments/identities/traits/test_traits_views.py +++ b/api/tests/unit/environments/identities/traits/test_traits_views.py @@ -6,6 +6,7 @@ VIEW_ENVIRONMENT, VIEW_IDENTITIES, ) +from common.projects.permissions import VIEW_PROJECT from core.constants import INTEGER, STRING from django.test import override_settings from django.urls import reverse @@ -25,7 +26,6 @@ from organisations.models import Organisation from permissions.models import PermissionModel from projects.models import Project, UserProjectPermission -from projects.permissions import VIEW_PROJECT def test_can_set_trait_for_an_identity( diff --git a/api/tests/unit/environments/permissions/test_unit_environments_permissions.py b/api/tests/unit/environments/permissions/test_unit_environments_permissions.py index 8c36ea8cabe5..f1fbcddbbf45 100644 --- a/api/tests/unit/environments/permissions/test_unit_environments_permissions.py +++ b/api/tests/unit/environments/permissions/test_unit_environments_permissions.py @@ -1,5 +1,7 @@ from unittest import mock +from common.projects.permissions import CREATE_ENVIRONMENT + from environments.identities.models import Identity from environments.models import Environment from environments.permissions.models import UserEnvironmentPermission @@ -13,7 +15,6 @@ ProjectPermissionModel, UserProjectPermission, ) -from projects.permissions import CREATE_ENVIRONMENT from users.models import FFAdminUser mock_view = mock.MagicMock() diff --git a/api/tests/unit/environments/test_unit_environments_views.py b/api/tests/unit/environments/test_unit_environments_views.py index 1929ff8ae396..d151fade2d52 100644 --- a/api/tests/unit/environments/test_unit_environments_views.py +++ b/api/tests/unit/environments/test_unit_environments_views.py @@ -3,6 +3,7 @@ import pytest from common.environments.permissions import VIEW_ENVIRONMENT +from common.projects.permissions import CREATE_ENVIRONMENT from core.constants import STRING from django.conf import settings from django.contrib.contenttypes.models import ContentType @@ -25,7 +26,6 @@ from metadata.models import Metadata, MetadataModelField from organisations.models import Organisation from projects.models import Project -from projects.permissions import CREATE_ENVIRONMENT from segments.models import Condition, Segment, SegmentRule from tests.types import WithEnvironmentPermissionsCallable from users.models import FFAdminUser diff --git a/api/tests/unit/features/feature_segments/test_unit_feature_segments_views.py b/api/tests/unit/features/feature_segments/test_unit_feature_segments_views.py index 0f9c5b76d26a..0e984f2ae543 100644 --- a/api/tests/unit/features/feature_segments/test_unit_feature_segments_views.py +++ b/api/tests/unit/features/feature_segments/test_unit_feature_segments_views.py @@ -6,6 +6,7 @@ UPDATE_FEATURE_STATE, VIEW_ENVIRONMENT, ) +from common.projects.permissions import VIEW_PROJECT from django.conf import settings from django.urls import reverse from pytest_django import DjangoAssertNumQueries @@ -20,7 +21,6 @@ from features.models import Feature, FeatureSegment, FeatureState from features.versioning.models import EnvironmentFeatureVersion from projects.models import Project, UserProjectPermission -from projects.permissions import VIEW_PROJECT from segments.models import Segment from tests.types import ( WithEnvironmentPermissionsCallable, diff --git a/api/tests/unit/features/import_export/test_unit_features_import_export_views.py b/api/tests/unit/features/import_export/test_unit_features_import_export_views.py index 7c45edbd4580..55dd5551674d 100644 --- a/api/tests/unit/features/import_export/test_unit_features_import_export_views.py +++ b/api/tests/unit/features/import_export/test_unit_features_import_export_views.py @@ -1,6 +1,7 @@ import json import pytest +from common.projects.permissions import VIEW_PROJECT from django.core.files.uploadedfile import SimpleUploadedFile from django.urls import reverse from pytest_django.fixtures import SettingsWrapper @@ -16,7 +17,6 @@ FlagsmithOnFlagsmithFeatureExport, ) from projects.models import Project -from projects.permissions import VIEW_PROJECT from projects.tags.models import Tag from tests.types import WithProjectPermissionsCallable from users.models import FFAdminUser diff --git a/api/tests/unit/features/multivariate/test_unit_multivariate_views.py b/api/tests/unit/features/multivariate/test_unit_multivariate_views.py index 89f2b355b6c8..84b7c53294cf 100644 --- a/api/tests/unit/features/multivariate/test_unit_multivariate_views.py +++ b/api/tests/unit/features/multivariate/test_unit_multivariate_views.py @@ -1,16 +1,13 @@ import uuid import pytest +from common.projects.permissions import CREATE_FEATURE, VIEW_PROJECT from django.urls import reverse from pytest_lazyfixture import lazy_fixture from rest_framework import status from features.multivariate.views import MultivariateFeatureOptionViewSet -from projects.permissions import ( - CREATE_FEATURE, - VIEW_PROJECT, - NestedProjectPermissions, -) +from projects.permissions import NestedProjectPermissions def test_multivariate_feature_options_view_set_get_permissions(): diff --git a/api/tests/unit/features/test_unit_features_permissions.py b/api/tests/unit/features/test_unit_features_permissions.py index e1dc4f864e64..46f437bbaa40 100644 --- a/api/tests/unit/features/test_unit_features_permissions.py +++ b/api/tests/unit/features/test_unit_features_permissions.py @@ -2,6 +2,11 @@ from unittest.mock import MagicMock import pytest +from common.projects.permissions import ( + CREATE_FEATURE, + DELETE_FEATURE, + VIEW_PROJECT, +) from features.models import Feature from features.permissions import FeaturePermissions @@ -12,12 +17,7 @@ UserPermissionGroupProjectPermission, UserProjectPermission, ) -from projects.permissions import ( - CREATE_FEATURE, - DELETE_FEATURE, - VIEW_PROJECT, - NestedProjectPermissions, -) +from projects.permissions import NestedProjectPermissions from tests.types import WithProjectPermissionsCallable from users.models import FFAdminUser, UserPermissionGroup diff --git a/api/tests/unit/features/test_unit_features_views.py b/api/tests/unit/features/test_unit_features_views.py index 3ea5296da5cb..248ecf656d3d 100644 --- a/api/tests/unit/features/test_unit_features_views.py +++ b/api/tests/unit/features/test_unit_features_views.py @@ -11,6 +11,7 @@ UPDATE_FEATURE_STATE, VIEW_ENVIRONMENT, ) +from common.projects.permissions import CREATE_FEATURE, VIEW_PROJECT from core.constants import FLAGSMITH_UPDATED_AT_HEADER from django.conf import settings from django.forms import model_to_dict @@ -41,7 +42,6 @@ from metadata.models import MetadataModelField from organisations.models import Organisation, OrganisationRole from projects.models import Project, UserProjectPermission -from projects.permissions import CREATE_FEATURE, VIEW_PROJECT from projects.tags.models import Tag from segments.models import Segment from tests.types import ( diff --git a/api/tests/unit/features/versioning/test_unit_versioning_views.py b/api/tests/unit/features/versioning/test_unit_versioning_views.py index 85933b3f505c..3cffd9ac8909 100644 --- a/api/tests/unit/features/versioning/test_unit_versioning_views.py +++ b/api/tests/unit/features/versioning/test_unit_versioning_views.py @@ -7,6 +7,7 @@ UPDATE_FEATURE_STATE, VIEW_ENVIRONMENT, ) +from common.projects.permissions import VIEW_PROJECT from core.constants import STRING from django.urls import reverse from django.utils import timezone @@ -26,7 +27,6 @@ from features.multivariate.models import MultivariateFeatureOption from features.versioning.models import EnvironmentFeatureVersion from projects.models import Project -from projects.permissions import VIEW_PROJECT from segments.models import Segment from tests.types import ( WithEnvironmentPermissionsCallable, diff --git a/api/tests/unit/permissions/permission_service/test_get_permitted_projects_for_user.py b/api/tests/unit/permissions/permission_service/test_get_permitted_projects_for_user.py index 2af30708882c..5820fde1bed2 100644 --- a/api/tests/unit/permissions/permission_service/test_get_permitted_projects_for_user.py +++ b/api/tests/unit/permissions/permission_service/test_get_permitted_projects_for_user.py @@ -1,13 +1,13 @@ import pytest -from pytest_lazyfixture import lazy_fixture - -from permissions.permission_service import get_permitted_projects_for_user -from projects.models import ProjectPermissionModel -from projects.permissions import ( +from common.projects.permissions import ( CREATE_ENVIRONMENT, DELETE_FEATURE, VIEW_PROJECT, ) +from pytest_lazyfixture import lazy_fixture + +from permissions.permission_service import get_permitted_projects_for_user +from projects.models import ProjectPermissionModel def test_get_permitted_projects_for_user_returns_all_projects_for_org_admin( diff --git a/api/tests/unit/permissions/test_unit_permissions_calculator.py b/api/tests/unit/permissions/test_unit_permissions_calculator.py index 20046c2115e8..cd89119b03de 100644 --- a/api/tests/unit/permissions/test_unit_permissions_calculator.py +++ b/api/tests/unit/permissions/test_unit_permissions_calculator.py @@ -3,6 +3,7 @@ UPDATE_FEATURE_STATE, VIEW_ENVIRONMENT, ) +from common.projects.permissions import CREATE_ENVIRONMENT, VIEW_PROJECT from environments.permissions.models import ( EnvironmentPermissionModel, @@ -29,7 +30,6 @@ UserPermissionGroupProjectPermission, UserProjectPermission, ) -from projects.permissions import CREATE_ENVIRONMENT, VIEW_PROJECT from users.models import UserPermissionGroup diff --git a/api/tests/unit/projects/tags/test_unit_projects_tags_permissions.py b/api/tests/unit/projects/tags/test_unit_projects_tags_permissions.py index e79c96828e1f..46121e7c4d28 100644 --- a/api/tests/unit/projects/tags/test_unit_projects_tags_permissions.py +++ b/api/tests/unit/projects/tags/test_unit_projects_tags_permissions.py @@ -1,7 +1,8 @@ from unittest import mock +from common.projects.permissions import MANAGE_TAGS, VIEW_PROJECT + from projects.models import Project -from projects.permissions import MANAGE_TAGS, VIEW_PROJECT from projects.tags.models import Tag from projects.tags.permissions import TagPermissions from tests.types import WithProjectPermissionsCallable diff --git a/api/tests/unit/projects/tags/test_unit_projects_tags_views.py b/api/tests/unit/projects/tags/test_unit_projects_tags_views.py index d1942cdbb6f6..f278e6821ca1 100644 --- a/api/tests/unit/projects/tags/test_unit_projects_tags_views.py +++ b/api/tests/unit/projects/tags/test_unit_projects_tags_views.py @@ -1,13 +1,13 @@ import json import pytest +from common.projects.permissions import VIEW_PROJECT from django.urls import reverse from pytest_lazyfixture import lazy_fixture from rest_framework import status from rest_framework.test import APIClient from projects.models import Project -from projects.permissions import VIEW_PROJECT from projects.tags.models import Tag from tests.types import WithProjectPermissionsCallable diff --git a/api/tests/unit/projects/test_migrations.py b/api/tests/unit/projects/test_migrations.py index 23c51b363c6d..20f3ef4b19dd 100644 --- a/api/tests/unit/projects/test_migrations.py +++ b/api/tests/unit/projects/test_migrations.py @@ -1,8 +1,7 @@ import pytest +from common.projects.permissions import CREATE_ENVIRONMENT, VIEW_PROJECT from django.conf import settings -from projects.permissions import CREATE_ENVIRONMENT, VIEW_PROJECT - @pytest.mark.skipif( settings.SKIP_MIGRATION_TESTS is True, diff --git a/api/tests/unit/projects/test_unit_projects_permissions.py b/api/tests/unit/projects/test_unit_projects_permissions.py index f7b874ab0b81..496aab1c0b68 100644 --- a/api/tests/unit/projects/test_unit_projects_permissions.py +++ b/api/tests/unit/projects/test_unit_projects_permissions.py @@ -2,17 +2,14 @@ from unittest import mock import pytest +from common.projects.permissions import VIEW_PROJECT from django.conf import settings from rest_framework.exceptions import APIException, PermissionDenied from organisations.models import Organisation, OrganisationRole from organisations.permissions.permissions import CREATE_PROJECT from projects.models import Project, UserPermissionGroupProjectPermission -from projects.permissions import ( - VIEW_PROJECT, - IsProjectAdmin, - ProjectPermissions, -) +from projects.permissions import IsProjectAdmin, ProjectPermissions from tests.types import ( WithOrganisationPermissionsCallable, WithProjectPermissionsCallable, diff --git a/api/tests/unit/projects/test_unit_projects_views.py b/api/tests/unit/projects/test_unit_projects_views.py index 1854336d76e9..8952c0ec1149 100644 --- a/api/tests/unit/projects/test_unit_projects_views.py +++ b/api/tests/unit/projects/test_unit_projects_views.py @@ -2,6 +2,11 @@ from datetime import timedelta import pytest +from common.projects.permissions import ( + CREATE_ENVIRONMENT, + CREATE_FEATURE, + VIEW_PROJECT, +) from django.urls import reverse from django.utils import timezone from pytest_django.fixtures import SettingsWrapper @@ -26,11 +31,6 @@ UserPermissionGroupProjectPermission, UserProjectPermission, ) -from projects.permissions import ( - CREATE_ENVIRONMENT, - CREATE_FEATURE, - VIEW_PROJECT, -) from segments.models import Segment from tests.types import WithProjectPermissionsCallable from users.models import FFAdminUser, UserPermissionGroup diff --git a/api/tests/unit/segments/test_unit_segments_permissions.py b/api/tests/unit/segments/test_unit_segments_permissions.py index b338c96b1d9f..5b6f92c8a1cc 100644 --- a/api/tests/unit/segments/test_unit_segments_permissions.py +++ b/api/tests/unit/segments/test_unit_segments_permissions.py @@ -1,11 +1,12 @@ import uuid from unittest import mock +from common.projects.permissions import VIEW_PROJECT + from environments.identities.models import Identity from environments.models import Environment from permissions.models import PermissionModel from projects.models import Project, UserProjectPermission -from projects.permissions import VIEW_PROJECT from segments.models import Segment from segments.permissions import SegmentPermissions from tests.types import ( diff --git a/api/tests/unit/segments/test_unit_segments_views.py b/api/tests/unit/segments/test_unit_segments_views.py index fb6c07d6d847..e3f5b4686e5a 100644 --- a/api/tests/unit/segments/test_unit_segments_views.py +++ b/api/tests/unit/segments/test_unit_segments_views.py @@ -2,6 +2,7 @@ import random import pytest +from common.projects.permissions import MANAGE_SEGMENTS, VIEW_PROJECT from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType @@ -21,7 +22,6 @@ from features.models import Feature from metadata.models import Metadata, MetadataModelField from projects.models import Project -from projects.permissions import MANAGE_SEGMENTS, VIEW_PROJECT from segments.models import Condition, Segment, SegmentRule, WhitelistedSegment from tests.types import WithProjectPermissionsCallable from util.mappers import map_identity_to_identity_document diff --git a/api/tests/unit/users/test_unit_users_models.py b/api/tests/unit/users/test_unit_users_models.py index fcc17d4a8157..8d4dcf32889d 100644 --- a/api/tests/unit/users/test_unit_users_models.py +++ b/api/tests/unit/users/test_unit_users_models.py @@ -1,11 +1,11 @@ import pytest +from common.projects.permissions import VIEW_PROJECT from django.db.utils import IntegrityError from organisations.models import Organisation, OrganisationRole from organisations.permissions.models import UserOrganisationPermission from organisations.permissions.permissions import ORGANISATION_PERMISSIONS from projects.models import Project -from projects.permissions import VIEW_PROJECT from tests.types import WithProjectPermissionsCallable from users.models import FFAdminUser From 9585cb153f269465ca71bd63cdc0c4e7cc4127a4 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 23 Oct 2024 19:16:58 +0000 Subject: [PATCH 116/122] Remove segment serializers --- api/segments/serializers.py | 250 +----------------------------------- 1 file changed, 1 insertion(+), 249 deletions(-) diff --git a/api/segments/serializers.py b/api/segments/serializers.py index 6b9e318c2917..644a8a4d804b 100644 --- a/api/segments/serializers.py +++ b/api/segments/serializers.py @@ -1,254 +1,6 @@ -import logging -import typing - -from common.metadata.serializers import ( - MetadataSerializer, - SerializerWithMetadata, -) -from django.conf import settings -from django.contrib.contenttypes.models import ContentType -from flag_engine.segments.constants import PERCENTAGE_SPLIT from rest_framework import serializers -from rest_framework.exceptions import ValidationError -from rest_framework.serializers import ListSerializer -from rest_framework_recursive.fields import RecursiveField - -from metadata.models import Metadata -from projects.models import Project -from segments.models import Condition, Segment, SegmentRule - -logger = logging.getLogger(__name__) - - -class ConditionSerializer(serializers.ModelSerializer): - delete = serializers.BooleanField(write_only=True, required=False) - - class Meta: - model = Condition - fields = ("id", "operator", "property", "value", "description", "delete") - - def validate(self, attrs): - super(ConditionSerializer, self).validate(attrs) - if attrs.get("operator") != PERCENTAGE_SPLIT and not attrs.get("property"): - raise ValidationError({"property": ["This field may not be blank."]}) - return attrs - - def to_internal_value(self, data): - # convert value to a string - conversion to correct value type is handled elsewhere - data["value"] = str(data["value"]) if "value" in data else None - return super(ConditionSerializer, self).to_internal_value(data) - - -class RuleSerializer(serializers.ModelSerializer): - delete = serializers.BooleanField(write_only=True, required=False) - conditions = ConditionSerializer(many=True, required=False) - rules = ListSerializer(child=RecursiveField(), required=False) - - class Meta: - model = SegmentRule - fields = ("id", "type", "rules", "conditions", "delete") - - -class SegmentSerializer(serializers.ModelSerializer, SerializerWithMetadata): - rules = RuleSerializer(many=True) - metadata = MetadataSerializer(required=False, many=True) - - class Meta: - model = Segment - fields = "__all__" - - def validate(self, attrs): - attrs = super().validate(attrs) - self.validate_required_metadata(attrs) - if not attrs.get("rules"): - raise ValidationError( - {"rules": "Segment cannot be created without any rules."} - ) - return attrs - - def get_project(self, validated_data: dict = None) -> Project: - return validated_data.get("project") or Project.objects.get( - id=self.context["view"].kwargs["project_pk"] - ) - - def create(self, validated_data): - project = validated_data["project"] - self.validate_project_segment_limit(project) - - rules_data = validated_data.pop("rules", []) - metadata_data = validated_data.pop("metadata", []) - self.validate_segment_rules_conditions_limit(rules_data) - - # create segment with nested rules and conditions - segment = Segment.objects.create(**validated_data) - self._update_or_create_segment_rules( - rules_data, segment=segment, is_create=True - ) - self._update_or_create_metadata(metadata_data, segment=segment) - return segment - - def update( - self, instance: Segment, validated_data: dict[str, typing.Any] - ) -> Segment: - # use the initial data since we need the ids included to determine which to update & which to create - rules_data = self.initial_data.pop("rules", []) - metadata_data = validated_data.pop("metadata", []) - self.validate_segment_rules_conditions_limit(rules_data) - - # Create a version of the segment now that we're updating. - cloned_segment = instance.deep_clone() - logger.info( - f"Updating cloned segment {cloned_segment.id} for original segment {instance.id}" - ) - - try: - self._update_segment_rules(rules_data, segment=instance) - self._update_or_create_metadata(metadata_data, segment=instance) - - # remove rules from validated data to prevent error trying to create segment with nested rules - del validated_data["rules"] - response = super().update(instance, validated_data) - except Exception: - # Since there was a problem during the update we now delete the cloned segment, - # since we no longer need a versioned segment. - instance.refresh_from_db() - instance.version = cloned_segment.version - instance.save() - cloned_segment.hard_delete() - raise - - return response - - def validate_project_segment_limit(self, project: Project) -> None: - if project.segments.count() >= project.max_segments_allowed: - raise ValidationError( - { - "project": "The project has reached the maximum allowed segments limit." - } - ) - - def validate_segment_rules_conditions_limit( - self, rules_data: dict[str, object] - ) -> None: - if self.instance and getattr(self.instance, "whitelisted_segment", None): - return - - count = self._calculate_condition_count(rules_data) - - if self.instance: - logger.info(f"Segment {self.instance.id} has count of conditions {count}") - - if count > settings.SEGMENT_RULES_CONDITIONS_LIMIT: - raise ValidationError( - { - "segment": f"The segment has {count} conditions, which exceeds the maximum " - f"condition count of {settings.SEGMENT_RULES_CONDITIONS_LIMIT}." - } - ) - - def _calculate_condition_count( - self, - rules_data: dict[str, object], - ) -> None: - count: int = 0 - - for rule_data in rules_data: - child_rules = rule_data.get("rules", []) - if child_rules: - count += self._calculate_condition_count(child_rules) - conditions = rule_data.get("conditions", []) - for condition in conditions: - if condition.get("delete", False) is True: - continue - count += 1 - return count - - def _update_segment_rules(self, rules_data, segment=None): - """ - Since we don't have a unique identifier for the rules / conditions for the update, we assume that the client - passes up the new configuration for the rules of the segment and simply wipe the old ones and create new ones - """ - # traverse the rules / conditions tree - if no ids are provided, then maintain the previous behaviour (clear - # existing rules and create the ones that were sent) - # note: we do this to preserve backwards compatibility after adding logic to include the id in requests - if not Segment.id_exists_in_rules_data(rules_data): - segment.rules.set([]) - - self._update_or_create_segment_rules(rules_data, segment=segment) - - def _update_or_create_segment_rules( - self, rules_data, segment=None, rule=None, is_create: bool = False - ): - if all(x is None for x in {segment, rule}): - raise RuntimeError("Can't create rule without parent segment or rule") - - for rule_data in rules_data: - child_rules = rule_data.pop("rules", []) - conditions = rule_data.pop("conditions", []) - - child_rule = self._update_or_create_segment_rule( - rule_data, segment=segment, rule=rule - ) - if not child_rule: - # child rule was deleted - continue - - self._update_or_create_conditions( - conditions, child_rule, is_create=is_create - ) - - self._update_or_create_segment_rules( - child_rules, rule=child_rule, is_create=is_create - ) - - def _update_or_create_metadata( - self, metadata_data: typing.Dict, segment: typing.Optional[Segment] = None - ) -> None: - if len(metadata_data) == 0: - Metadata.objects.filter(object_id=segment.id).delete() - return - if metadata_data is not None: - for metadata_item in metadata_data: - metadata_model_field = metadata_item.pop("model_field", None) - if metadata_item.get("delete"): - Metadata.objects.filter(model_field=metadata_model_field).delete() - continue - - Metadata.objects.update_or_create( - model_field=metadata_model_field, - defaults={ - **metadata_item, - "content_type": ContentType.objects.get_for_model(Segment), - "object_id": segment.id, - }, - ) - - @staticmethod - def _update_or_create_segment_rule( - rule_data: dict, segment: None | Segment = None, rule: None | SegmentRule = None - ) -> None | SegmentRule: - rule_id = rule_data.pop("id", None) - if rule_data.get("delete"): - SegmentRule.objects.filter(id=rule_id).delete() - return - - segment_rule, _ = SegmentRule.objects.update_or_create( - id=rule_id, defaults={"segment": segment, "rule": rule, **rule_data} - ) - return segment_rule - - @staticmethod - def _update_or_create_conditions(conditions_data, rule, is_create: bool = False): - for condition in conditions_data: - condition_id = condition.pop("id", None) - if condition.get("delete"): - Condition.objects.filter(id=condition_id).delete() - continue - Condition.objects.update_or_create( - id=condition_id, - defaults={**condition, "created_with_segment": is_create, "rule": rule}, - ) +from segments.models import Segment class SegmentSerializerBasic(serializers.ModelSerializer): From e3adf43c8fd70c555f3d5b5c7d8a4b7216fa30bf Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 23 Oct 2024 19:22:54 +0000 Subject: [PATCH 117/122] Update to common library for segments serializers --- api/segments/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/segments/views.py b/api/segments/views.py index 363bada84fab..cad4880b1c51 100644 --- a/api/segments/views.py +++ b/api/segments/views.py @@ -1,6 +1,7 @@ import logging from common.projects.permissions import VIEW_PROJECT +from common.segments.serializers import SegmentSerializer from django.utils.decorators import method_decorator from drf_yasg.utils import swagger_auto_schema from rest_framework import viewsets @@ -16,7 +17,7 @@ from .models import Segment from .permissions import SegmentPermissions -from .serializers import SegmentListQuerySerializer, SegmentSerializer +from .serializers import SegmentListQuerySerializer logger = logging.getLogger() From c9b96f081d80585311aaad000d51f64997a9ef6a Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 23 Oct 2024 19:25:40 +0000 Subject: [PATCH 118/122] Disable test coverage due to refactor --- api/e2etests/e2e_seed_data.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/e2etests/e2e_seed_data.py b/api/e2etests/e2e_seed_data.py index 592b4a6de490..37b7605e2a17 100644 --- a/api/e2etests/e2e_seed_data.py +++ b/api/e2etests/e2e_seed_data.py @@ -196,10 +196,10 @@ def seed_data() -> None: for identity_info in identities_test_data: if settings.IDENTITIES_TABLE_NAME_DYNAMO: - engine_identity = EngineIdentity( + engine_identity = EngineIdentity( # pragma: no cover identifier=identity_info["identifier"], environment_api_key=identity_info["environment"].api_key, ) - EdgeIdentity(engine_identity).save() + EdgeIdentity(engine_identity).save() # pragma: no cover else: Identity.objects.create(**identity_info) From f02d22954473d1a08d8c51c3d1e433da56c175b7 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Tue, 29 Oct 2024 15:46:29 +0000 Subject: [PATCH 119/122] Update segment manager calls --- api/integrations/dynatrace/dynatrace.py | 2 +- api/integrations/launch_darkly/services.py | 6 +++--- api/projects/models.py | 7 ++++++- api/projects/serializers.py | 2 +- .../templates/sales_dashboard/organisation.html | 2 +- api/segments/views.py | 2 +- api/util/mappers/engine.py | 4 +++- 7 files changed, 16 insertions(+), 9 deletions(-) diff --git a/api/integrations/dynatrace/dynatrace.py b/api/integrations/dynatrace/dynatrace.py index 0a448d24a27b..d888e668c0ef 100644 --- a/api/integrations/dynatrace/dynatrace.py +++ b/api/integrations/dynatrace/dynatrace.py @@ -95,7 +95,7 @@ def _get_deployment_name_for_feature( def _get_deployment_name_for_segment(object_id: int) -> str: - if segment := Segment.objects.all_with_deleted().filter(id=object_id).first(): + if segment := Segment.live_objects.all_with_deleted().filter(id=object_id).first(): return f"Flagsmith Deployment - Segment Changed: {segment.name}" return DEFAULT_DEPLOYMENT_NAME diff --git a/api/integrations/launch_darkly/services.py b/api/integrations/launch_darkly/services.py index c4650a44b6b1..a0a480733b50 100644 --- a/api/integrations/launch_darkly/services.py +++ b/api/integrations/launch_darkly/services.py @@ -241,7 +241,7 @@ def _create_feature_segments_for_segment_match_clauses( targeted_segment_name = segments_by_ld_key[targeted_segment_key].name # We assume segment is already created. - segment = Segment.objects.get(name=targeted_segment_name, project=project) + segment = Segment.live_objects.get(name=targeted_segment_name, project=project) feature_segment, _ = FeatureSegment.objects.update_or_create( feature=feature, @@ -368,7 +368,7 @@ def _create_feature_segment_from_clauses( ) # Create a feature specific segment for the rule. - segment, _ = Segment.objects.update_or_create( + segment, _ = Segment.live_objects.update_or_create( name=rule_name, project=project, feature=feature ) @@ -961,7 +961,7 @@ def _create_segments_from_ld( continue # Make sure consecutive updates do not create the same segment. - segment, _ = Segment.objects.update_or_create( + segment, _ = Segment.live_objects.update_or_create( name=_get_segment_name(ld_segment["name"], env), project_id=project_id, ) diff --git a/api/projects/models.py b/api/projects/models.py index d63a9980c181..0eee8a630b66 100644 --- a/api/projects/models.py +++ b/api/projects/models.py @@ -120,7 +120,7 @@ def __str__(self): def is_too_large(self) -> bool: return ( self.features.count() > self.max_features_allowed - or self.segments.count() > self.max_segments_allowed + or self.live_segment_count() > self.max_segments_allowed or self.environments.annotate( segment_override_count=Count("feature_segments") ) @@ -188,6 +188,11 @@ def is_edge_project_by_default(self) -> bool: and self.created_date >= settings.EDGE_RELEASE_DATETIME ) + def live_segment_count(self) -> int: + from segments.models import Segment + + return Segment.live_objects.filter(project=self).count() + def is_feature_name_valid(self, feature_name: str) -> bool: """ Validate the feature name based on the feature_name_regex attribute. diff --git a/api/projects/serializers.py b/api/projects/serializers.py index 9609c3fd7efa..1b14eb55ea83 100644 --- a/api/projects/serializers.py +++ b/api/projects/serializers.py @@ -119,7 +119,7 @@ def get_total_features(self, instance: Project) -> int: def get_total_segments(self, instance: Project) -> int: # added here to prevent need for annotate(Count("segments", distinct=True)) # which causes performance issues. - return instance.segments.count() + return instance.live_segment_count() class CreateUpdateUserProjectPermissionSerializer( diff --git a/api/sales_dashboard/templates/sales_dashboard/organisation.html b/api/sales_dashboard/templates/sales_dashboard/organisation.html index f0e7563a973f..3ae4faa87db0 100644 --- a/api/sales_dashboard/templates/sales_dashboard/organisation.html +++ b/api/sales_dashboard/templates/sales_dashboard/organisation.html @@ -129,7 +129,7 @@

Projects

{{project.name}} {{project.environments.all.count}} {{project.features.all.count}} - {{project.segments.all.count}} + {{project.live_segment_count}} {{project.enable_dynamo_db}} {{identity_count_dict|get_item:project.id|intcomma}} {{identity_migration_status_dict|get_item:project.id}} diff --git a/api/segments/views.py b/api/segments/views.py index cad4880b1c51..1ba6bc4bd5f5 100644 --- a/api/segments/views.py +++ b/api/segments/views.py @@ -101,7 +101,7 @@ def associated_features(self, request, *args, **kwargs): @api_view(["GET"]) def get_segment_by_uuid(request, uuid): accessible_projects = request.user.get_permitted_projects(VIEW_PROJECT) - qs = Segment.objects.filter(project__in=accessible_projects) + qs = Segment.live_objects.filter(project__in=accessible_projects) segment = get_object_or_404(qs, uuid=uuid) serializer = SegmentSerializer(instance=segment) return Response(serializer.data) diff --git a/api/util/mappers/engine.py b/api/util/mappers/engine.py index 6d4890bf229e..ca526733640a 100644 --- a/api/util/mappers/engine.py +++ b/api/util/mappers/engine.py @@ -199,7 +199,9 @@ def map_environment_to_engine( # Because of the queryset parameter of the calling code's # Prefetch this queryset will actually load the live_objects # manager for the Segment lookup. - project_segments: List["Segment"] = project.segments.all() + project_segments: List["Segment"] = Segment.live_objects.filter( + project=project + ).all() # Even though the main calling code filters via a prefetch, # we still want to guard this function in case there are other From e4f15512c0877494259a424e0b9c5e4073b79c80 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 13 Nov 2024 16:49:22 +0000 Subject: [PATCH 120/122] Add filter for live segments --- api/import_export/export.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/import_export/export.py b/api/import_export/export.py index fd373bbc7255..efcdf630a1e5 100644 --- a/api/import_export/export.py +++ b/api/import_export/export.py @@ -114,7 +114,9 @@ def export_projects(organisation_id: int) -> typing.List[dict]: return _export_entities( _EntityExportConfig(Project, Q(organisation__id=organisation_id)), - _EntityExportConfig(Segment, default_filter), + _EntityExportConfig( + Segment, Q(project__organisation__id=organisation_id, id=F("version_of")) + ), _EntityExportConfig( SegmentRule, Q( From f47922e53736b593136b53f11a1c96da53d612b6 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Wed, 13 Nov 2024 16:49:52 +0000 Subject: [PATCH 121/122] Just use the default manager and filter in code --- api/util/mappers/engine.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/api/util/mappers/engine.py b/api/util/mappers/engine.py index ca526733640a..411d4f0ffa3f 100644 --- a/api/util/mappers/engine.py +++ b/api/util/mappers/engine.py @@ -196,17 +196,9 @@ def map_environment_to_engine( # Read relationships - grab all the data needed from the ORM here. - # Because of the queryset parameter of the calling code's - # Prefetch this queryset will actually load the live_objects - # manager for the Segment lookup. - project_segments: List["Segment"] = Segment.live_objects.filter( - project=project - ).all() - - # Even though the main calling code filters via a prefetch, - # we still want to guard this function in case there are other - # callers in the future. - project_segments = [ps for ps in project_segments if ps.id == ps.version_of_id] + project_segments = [ + ps for ps in project.segments.all() if ps.id == ps.version_of_id + ] project_segment_rules_by_segment_id: Dict[ int, From 8bcebe44d8dffbb57e067b2187b4f856e2591293 Mon Sep 17 00:00:00 2001 From: Zach Aysan Date: Thu, 21 Nov 2024 19:22:02 +0000 Subject: [PATCH 122/122] Switch to tag for workflows --- api/poetry.lock | 6 +++--- api/pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index 5b4a232fc8b9..ba834dbae554 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -4066,8 +4066,8 @@ flagsmith-flag-engine = "*" [package.source] type = "git" url = "https://github.com/flagsmith/flagsmith-workflows" -reference = "feat/add_change_requests_to_segments" -resolved_reference = "4756d1b241133be3cb213eeaf70765031bb2ee2d" +reference = "v2.6.0" +resolved_reference = "06b03d428484f5aed2f400cef431ab5aae0d0df0" [[package]] name = "wrapt" @@ -4186,4 +4186,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.11, <3.13" -content-hash = "7ca18174be8caa1f4fdc5bdee521a4589348290d4534abc60ee63cfca6567c61" +content-hash = "df2e02787204f56111c560faa7f7800a09e87e9bdc0b9802660af5bd08aa03ee" diff --git a/api/pyproject.toml b/api/pyproject.toml index cfe4f60ee3db..90a75efd26d8 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -196,7 +196,7 @@ flagsmith-ldap = { git = "https://github.com/flagsmith/flagsmith-ldap", tag = "v optional = true [tool.poetry.group.workflows.dependencies] -workflows-logic = { git = "https://github.com/flagsmith/flagsmith-workflows", branch = "feat/add_change_requests_to_segments" } +workflows-logic = { git = "https://github.com/flagsmith/flagsmith-workflows", tag = "v2.6.0" } [tool.poetry.group.dev.dependencies] django-test-migrations = "~1.2.0"