From 403fb4037bd50ca47f4e5bb031afdd8fe45f300e Mon Sep 17 00:00:00 2001 From: Jesper Hodge Date: Tue, 24 Jun 2025 12:54:03 -0400 Subject: [PATCH 01/13] feat: add consumer receiver signal handler --- enterprise_access/apps/core/signals.py | 17 +++++++++++++++++ .../apps/enterprise_groups/signals.py | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 enterprise_access/apps/core/signals.py create mode 100644 enterprise_access/apps/enterprise_groups/signals.py diff --git a/enterprise_access/apps/core/signals.py b/enterprise_access/apps/core/signals.py new file mode 100644 index 000000000..7f253d2f5 --- /dev/null +++ b/enterprise_access/apps/core/signals.py @@ -0,0 +1,17 @@ +""" +Signal handlers for content_assignments app. +""" +import logging + +from django.dispatch import receiver +from openedx_events.enterprise.signals import ENTERPRISE_GROUP_DELETED + + +logger = logging.getLogger(__name__) + +@receiver(ENTERPRISE_GROUP_DELETED) +def handle_enterprise_group_deleted(**kwargs): + """ + OEP-49 event handler to update assignment status for reversed transaction. + """ + logger.info('Received ENTERPRISE_GROUP_DELETED signal with data: %s', kwargs) diff --git a/enterprise_access/apps/enterprise_groups/signals.py b/enterprise_access/apps/enterprise_groups/signals.py new file mode 100644 index 000000000..7f253d2f5 --- /dev/null +++ b/enterprise_access/apps/enterprise_groups/signals.py @@ -0,0 +1,17 @@ +""" +Signal handlers for content_assignments app. +""" +import logging + +from django.dispatch import receiver +from openedx_events.enterprise.signals import ENTERPRISE_GROUP_DELETED + + +logger = logging.getLogger(__name__) + +@receiver(ENTERPRISE_GROUP_DELETED) +def handle_enterprise_group_deleted(**kwargs): + """ + OEP-49 event handler to update assignment status for reversed transaction. + """ + logger.info('Received ENTERPRISE_GROUP_DELETED signal with data: %s', kwargs) From 1c20d56a2a9131abb4ae4487a6845d644cffca05 Mon Sep 17 00:00:00 2001 From: Jesper Hodge Date: Tue, 24 Jun 2025 15:02:28 -0400 Subject: [PATCH 02/13] feat: add consumer --- enterprise_access/apps/subsidy_access_policy/apps.py | 6 ++++++ .../{enterprise_groups => subsidy_access_policy}/signals.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) rename enterprise_access/apps/{enterprise_groups => subsidy_access_policy}/signals.py (90%) diff --git a/enterprise_access/apps/subsidy_access_policy/apps.py b/enterprise_access/apps/subsidy_access_policy/apps.py index a5ec244f3..5306174eb 100644 --- a/enterprise_access/apps/subsidy_access_policy/apps.py +++ b/enterprise_access/apps/subsidy_access_policy/apps.py @@ -6,3 +6,9 @@ class SubsidyAccessPolicyConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'enterprise_access.apps.subsidy_access_policy' + + def ready(self): + super().ready() + + # pylint: disable=unused-import, import-outside-toplevel + import enterprise_access.apps.subsidy_access_policy.signals diff --git a/enterprise_access/apps/enterprise_groups/signals.py b/enterprise_access/apps/subsidy_access_policy/signals.py similarity index 90% rename from enterprise_access/apps/enterprise_groups/signals.py rename to enterprise_access/apps/subsidy_access_policy/signals.py index 7f253d2f5..e4f4d1602 100644 --- a/enterprise_access/apps/enterprise_groups/signals.py +++ b/enterprise_access/apps/subsidy_access_policy/signals.py @@ -1,5 +1,5 @@ """ -Signal handlers for content_assignments app. +Signal handlers for subsidy_access_policy app. """ import logging From 0f4910e043d5f2a536af7e8ea38a29d36b6aa626 Mon Sep 17 00:00:00 2001 From: Jesper Hodge Date: Tue, 24 Jun 2025 17:00:20 -0400 Subject: [PATCH 03/13] feat: add cascade delete --- .../apps/subsidy_access_policy/models.py | 11 +++++++++++ .../apps/subsidy_access_policy/signals.py | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/enterprise_access/apps/subsidy_access_policy/models.py b/enterprise_access/apps/subsidy_access_policy/models.py index 60ef604bc..584cb7eb2 100644 --- a/enterprise_access/apps/subsidy_access_policy/models.py +++ b/enterprise_access/apps/subsidy_access_policy/models.py @@ -1668,6 +1668,17 @@ class Meta: help_text='The uuid that uniquely identifies the associated group.', ) + @classmethod + def cascade_delete_for_group_uuid(cls, group_uuid): + """ + Delete all associations for a remote EnterpriseGroup. + + Called by the domain signal `handle_enterprise_group_deleted`. + """ + return cls.objects.filter( + enterprise_group_uuid=group_uuid + ).delete() + class ForcedPolicyRedemption(TimeStampedModel): """ diff --git a/enterprise_access/apps/subsidy_access_policy/signals.py b/enterprise_access/apps/subsidy_access_policy/signals.py index e4f4d1602..3a3cbccde 100644 --- a/enterprise_access/apps/subsidy_access_policy/signals.py +++ b/enterprise_access/apps/subsidy_access_policy/signals.py @@ -5,6 +5,7 @@ from django.dispatch import receiver from openedx_events.enterprise.signals import ENTERPRISE_GROUP_DELETED +from enterprise_access.apps.subsidy_access_policy.models import PolicyGroupAssociation logger = logging.getLogger(__name__) @@ -15,3 +16,9 @@ def handle_enterprise_group_deleted(**kwargs): OEP-49 event handler to update assignment status for reversed transaction. """ logger.info('Received ENTERPRISE_GROUP_DELETED signal with data: %s', kwargs) + group_uuid = kwargs.get('enterprise_group', {}).get('uuid') + if not group_uuid: + logger.warning('ENTERPRISE_GROUP_DELETED signal received without a valid group UUID.') + return + deletions = PolicyGroupAssociation.cascade_delete_for_group_uuid(group_uuid) + logger.info('PolicyGroupAssociation records deleted: %s', deletions) From ce463269556bb36230102cf6095cd71bba0bbe72 Mon Sep 17 00:00:00 2001 From: Jesper Hodge Date: Thu, 10 Jul 2025 17:34:50 -0400 Subject: [PATCH 04/13] fix: group uuid object --- enterprise_access/apps/content_assignments/signals.py | 2 +- enterprise_access/apps/subsidy_access_policy/signals.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/enterprise_access/apps/content_assignments/signals.py b/enterprise_access/apps/content_assignments/signals.py index e4ba96244..ec06af4c2 100644 --- a/enterprise_access/apps/content_assignments/signals.py +++ b/enterprise_access/apps/content_assignments/signals.py @@ -6,7 +6,7 @@ from django.db.models.signals import post_save from django.dispatch import receiver from django.utils import timezone -from openedx_events.enterprise.signals import LEDGER_TRANSACTION_REVERSED +from openedx_events.enterprise.signals import LEDGER_TRANSACTION_REVERSED, ENTERPRISE_GROUP_DELETED from enterprise_access.apps.content_assignments.constants import LearnerContentAssignmentStateChoices from enterprise_access.apps.content_assignments.models import LearnerContentAssignment diff --git a/enterprise_access/apps/subsidy_access_policy/signals.py b/enterprise_access/apps/subsidy_access_policy/signals.py index 3a3cbccde..c9d6cd69a 100644 --- a/enterprise_access/apps/subsidy_access_policy/signals.py +++ b/enterprise_access/apps/subsidy_access_policy/signals.py @@ -16,9 +16,11 @@ def handle_enterprise_group_deleted(**kwargs): OEP-49 event handler to update assignment status for reversed transaction. """ logger.info('Received ENTERPRISE_GROUP_DELETED signal with data: %s', kwargs) - group_uuid = kwargs.get('enterprise_group', {}).get('uuid') + group_uuid = kwargs.get('enterprise_group').uuid if 'enterprise_group' in kwargs else None if not group_uuid: logger.warning('ENTERPRISE_GROUP_DELETED signal received without a valid group UUID.') return deletions = PolicyGroupAssociation.cascade_delete_for_group_uuid(group_uuid) logger.info('PolicyGroupAssociation records deleted: %s', deletions) + + # error handling \ No newline at end of file From be6c9c4cc86fdbdfb633e6d86a9be4a5414ab37e Mon Sep 17 00:00:00 2001 From: Jesper Hodge Date: Mon, 14 Jul 2025 18:33:31 -0400 Subject: [PATCH 05/13] chore: add docker container for consumer --- docker-compose.yml | 35 ++++++++++++++++++++++++++++++ enterprise_access/settings/base.py | 6 +++++ 2 files changed, 41 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 2da0a6bb6..c9d4f9693 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -99,6 +99,41 @@ services: CELERY_BROKER_PASSWORD: password DJANGO_SETTINGS_MODULE: enterprise_access.settings.devstack + consume_enterprise_group_events: + image: edxops/enterprise-access-dev + container_name: enterprise_access.consume_enterprise_group_events + volumes: + - .:/edx/app/enterprise-access/ + - ../src:/edx/src + command: > + bash -c ' + make requirements && + pip install edx-event-bus-kafka && + pip install -e /edx/src/openedx-events && + pip install "confluent-kafka[avro,schema-registry]" && + while true; do python /edx/app/enterprise-access/manage.py consume_events -t enterprise-core -g enterprise_access_dev; sleep 2; done + ' + ports: + - "18973:18973" + depends_on: + - mysql80 + - memcache + networks: + - devstack_default + stdin_open: true + tty: true + environment: + CELERY_ALWAYS_EAGER: 'false' + CELERY_BROKER_TRANSPORT: redis + CELERY_BROKER_HOSTNAME: edx.devstack.redis:6379 + CELERY_BROKER_VHOST: 0 + CELERY_BROKER_PASSWORD: password + EVENT_BUS_KAFKA_SCHEMA_REGISTRY_URL: 'http://edx.devstack.schema-registry:8081' + EVENT_BUS_KAFKA_BOOTSTRAP_SERVERS: 'edx.devstack.kafka:29092' + EVENT_BUS_PRODUCER: 'edx_event_bus_kafka.create_producer' + EVENT_BUS_CONSUMER: 'edx_event_bus_kafka.KafkaEventConsumer' + EVENT_BUS_TOPIC_PREFIX: 'dev' + networks: devstack_default: external: true diff --git a/enterprise_access/settings/base.py b/enterprise_access/settings/base.py index ed9776243..a0da1d67f 100644 --- a/enterprise_access/settings/base.py +++ b/enterprise_access/settings/base.py @@ -558,3 +558,9 @@ def root(*path_fragments): 'catalog_query_id': 1, }, } + +EVENT_BUS_KAFKA_SCHEMA_REGISTRY_URL = 'http://edx.devstack.schema-registry:8081' +EVENT_BUS_KAFKA_BOOTSTRAP_SERVERS = 'edx.devstack.kafka:29092' +EVENT_BUS_PRODUCER = 'edx_event_bus_kafka.create_producer' +EVENT_BUS_CONSUMER = 'edx_event_bus_kafka.KafkaEventConsumer' +EVENT_BUS_TOPIC_PREFIX = 'dev' From 720792add35310579e88e9c13bd0e12069e1fd03 Mon Sep 17 00:00:00 2001 From: Jesper Hodge Date: Wed, 16 Jul 2025 13:47:57 -0400 Subject: [PATCH 06/13] fix: docker container --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index c9d4f9693..ee9af6ede 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -133,6 +133,7 @@ services: EVENT_BUS_PRODUCER: 'edx_event_bus_kafka.create_producer' EVENT_BUS_CONSUMER: 'edx_event_bus_kafka.KafkaEventConsumer' EVENT_BUS_TOPIC_PREFIX: 'dev' + DJANGO_SETTINGS_MODULE: enterprise_access.settings.devstack networks: devstack_default: From 8b6aebc46dbc33c4218137d0e892a3b60526036a Mon Sep 17 00:00:00 2001 From: Jesper Hodge Date: Mon, 21 Jul 2025 17:32:18 -0400 Subject: [PATCH 07/13] chore: change topic name and docker port --- docker-compose.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index ee9af6ede..c05af9c5b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -99,9 +99,9 @@ services: CELERY_BROKER_PASSWORD: password DJANGO_SETTINGS_MODULE: enterprise_access.settings.devstack - consume_enterprise_group_events: + consume_enterprise_groups_lifecycle: image: edxops/enterprise-access-dev - container_name: enterprise_access.consume_enterprise_group_events + container_name: enterprise_access.consume_enterprise_groups_lifecycle volumes: - .:/edx/app/enterprise-access/ - ../src:/edx/src @@ -111,10 +111,10 @@ services: pip install edx-event-bus-kafka && pip install -e /edx/src/openedx-events && pip install "confluent-kafka[avro,schema-registry]" && - while true; do python /edx/app/enterprise-access/manage.py consume_events -t enterprise-core -g enterprise_access_dev; sleep 2; done + while true; do python /edx/app/enterprise-access/manage.py consume_events -t enterprise-groups-lifecycle -g enterprise_access_dev; sleep 2; done ' ports: - - "18973:18973" + - "18273:18273" depends_on: - mysql80 - memcache From a513f4cce2b7dc248bb049929e54ecc8b5feaf1c Mon Sep 17 00:00:00 2001 From: jesperhodge Date: Thu, 14 Aug 2025 12:20:56 -0400 Subject: [PATCH 08/13] feat: make setup for enterprise group deletion consumer work --- docker-compose.yml | 2 +- .../subsidy_access_policy/tests/factories.py | 2 +- enterprise_access/settings/base.py | 8 +- enterprise_access/settings/devstack.py | 2 + enterprise_access/settings/test.py | 2 + requirements/base.txt | 82 +++++------ requirements/common_constraints.txt | 7 - requirements/dev.txt | 132 +++++++++--------- requirements/django.txt | 2 +- requirements/doc.txt | 115 +++++++-------- requirements/pip-tools.txt | 6 +- requirements/pip.txt | 4 +- requirements/production.txt | 80 +++++------ requirements/quality.txt | 123 ++++++++-------- requirements/test.txt | 110 ++++++++------- requirements/validation.txt | 123 ++++++++-------- 16 files changed, 401 insertions(+), 399 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index c05af9c5b..6e2b7746a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -109,7 +109,7 @@ services: bash -c ' make requirements && pip install edx-event-bus-kafka && - pip install -e /edx/src/openedx-events && + pip install openedx-events>=10.4.0 && pip install "confluent-kafka[avro,schema-registry]" && while true; do python /edx/app/enterprise-access/manage.py consume_events -t enterprise-groups-lifecycle -g enterprise_access_dev; sleep 2; done ' diff --git a/enterprise_access/apps/subsidy_access_policy/tests/factories.py b/enterprise_access/apps/subsidy_access_policy/tests/factories.py index 8e0602b65..2c73f88ac 100644 --- a/enterprise_access/apps/subsidy_access_policy/tests/factories.py +++ b/enterprise_access/apps/subsidy_access_policy/tests/factories.py @@ -78,7 +78,7 @@ class Meta: model = PolicyGroupAssociation enterprise_group_uuid = factory.LazyFunction(uuid4) - subsidy_access_policy = factory.SubFactory(SubsidyAccessPolicyFactory) + subsidy_access_policy = factory.SubFactory(PerLearnerEnrollmentCapLearnerCreditAccessPolicyFactory) class ForcedPolicyRedemptionFactory(factory.django.DjangoModelFactory): diff --git a/enterprise_access/settings/base.py b/enterprise_access/settings/base.py index a0da1d67f..259c7c141 100644 --- a/enterprise_access/settings/base.py +++ b/enterprise_access/settings/base.py @@ -455,9 +455,11 @@ def root(*path_fragments): LICENSE_REQUEST_TOPIC_NAME = "license-request" ACCESS_POLICY_TOPIC_NAME = "access-policy" SUBSIDY_REDEMPTION_TOPIC_NAME = "subsidy-redemption" +ENTERPRISE_GROUPS_LIFECYCLE_TOPIC_NAME = "enterprise-groups-lifecycle" KAFKA_TOPICS = [ COUPON_CODE_REQUEST_TOPIC_NAME, LICENSE_REQUEST_TOPIC_NAME, + ENTERPRISE_GROUPS_LIFECYCLE_TOPIC_NAME, # Access policy events ACCESS_POLICY_TOPIC_NAME, @@ -558,9 +560,3 @@ def root(*path_fragments): 'catalog_query_id': 1, }, } - -EVENT_BUS_KAFKA_SCHEMA_REGISTRY_URL = 'http://edx.devstack.schema-registry:8081' -EVENT_BUS_KAFKA_BOOTSTRAP_SERVERS = 'edx.devstack.kafka:29092' -EVENT_BUS_PRODUCER = 'edx_event_bus_kafka.create_producer' -EVENT_BUS_CONSUMER = 'edx_event_bus_kafka.KafkaEventConsumer' -EVENT_BUS_TOPIC_PREFIX = 'dev' diff --git a/enterprise_access/settings/devstack.py b/enterprise_access/settings/devstack.py index 982e537aa..4e17c13f5 100644 --- a/enterprise_access/settings/devstack.py +++ b/enterprise_access/settings/devstack.py @@ -129,9 +129,11 @@ LICENSE_REQUEST_TOPIC_NAME = "license-request-dev" ACCESS_POLICY_TOPIC_NAME = "access-policy-dev" SUBSIDY_REDEMPTION_TOPIC_NAME = "subsidy-redemption-dev" +ENTERPRISE_GROUPS_LIFECYCLE_TOPIC_NAME = "enterprise-groups-lifecycle-dev" KAFKA_TOPICS = [ COUPON_CODE_REQUEST_TOPIC_NAME, LICENSE_REQUEST_TOPIC_NAME, + ENTERPRISE_GROUPS_LIFECYCLE_TOPIC_NAME, # Access policy events ACCESS_POLICY_TOPIC_NAME, diff --git a/enterprise_access/settings/test.py b/enterprise_access/settings/test.py index 11713a428..b763579a6 100644 --- a/enterprise_access/settings/test.py +++ b/enterprise_access/settings/test.py @@ -66,9 +66,11 @@ LICENSE_REQUEST_TOPIC_NAME = "license-request-test" ACCESS_POLICY_TOPIC_NAME = "access-policy-test" SUBSIDY_REDEMPTION_TOPIC_NAME = "subsidy-redemption-test" +ENTERPRISE_GROUPS_LIFECYCLE_TOPIC_NAME = "enterprise-groups-lifecycle-test" KAFKA_TOPICS = [ COUPON_CODE_REQUEST_TOPIC_NAME, LICENSE_REQUEST_TOPIC_NAME, + ENTERPRISE_GROUPS_LIFECYCLE_TOPIC_NAME, # Access policy events ACCESS_POLICY_TOPIC_NAME, diff --git a/requirements/base.txt b/requirements/base.txt index 7ca7f91ef..07f529eb0 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -8,7 +8,7 @@ amqp==5.3.1 # via kombu analytics-python==1.4.post1 # via -r requirements/base.in -asgiref==3.8.1 +asgiref==3.9.1 # via # django # django-cors-headers @@ -25,22 +25,22 @@ backoff==1.10.0 # via analytics-python billiard==4.2.1 # via celery -cattrs==24.1.3 +cattrs==25.1.1 # via -r requirements/base.in -celery==5.5.2 +celery==5.5.3 # via # -r requirements/base.in # django-celery-results # edx-celeryutils -certifi==2025.4.26 +certifi==2025.8.3 # via requests cffi==1.17.1 # via # cryptography # pynacl -charset-normalizer==3.4.2 +charset-normalizer==3.4.3 # via requests -click==8.1.8 +click==8.2.1 # via # celery # click-didyoumean @@ -50,7 +50,7 @@ click==8.1.8 # edx-django-utils click-didyoumean==0.3.1 # via celery -click-plugins==1.1.1 +click-plugins==1.1.1.2 # via celery click-repl==0.3.0 # via celery @@ -66,7 +66,7 @@ coreapi==2.3.3 # openapi-codec coreschema==0.0.4 # via coreapi -cryptography==44.0.3 +cryptography==45.0.6 # via # pyjwt # social-auth-core @@ -74,7 +74,7 @@ defusedxml==0.7.1 # via # python3-openid # social-auth-core -django==4.2.20 +django==4.2.23 # via # -c requirements/common_constraints.txt # -r requirements/base.in @@ -130,9 +130,9 @@ django-object-actions==5.0.0 # via -r requirements/base.in django-rest-swagger==2.2.0 # via -r requirements/base.in -django-simple-history==3.8.0 +django-simple-history==3.10.1 # via -r requirements/base.in -django-waffle==4.2.0 +django-waffle==5.0.0 # via # -r requirements/base.in # edx-django-utils @@ -140,7 +140,7 @@ django-waffle==4.2.0 # edx-toggles djangoql==0.18.1 # via -r requirements/base.in -djangorestframework==3.16.0 +djangorestframework==3.16.1 # via # -r requirements/base.in # django-rest-swagger @@ -162,7 +162,7 @@ drf-yasg==1.21.10 # via edx-api-doc-tools edx-api-doc-tools==2.1.0 # via -r requirements/base.in -edx-auth-backends==4.5.0 +edx-auth-backends==4.6.0 # via -r requirements/base.in edx-braze-client==0.2.5 # via @@ -170,13 +170,14 @@ edx-braze-client==0.2.5 # -r requirements/base.in edx-ccx-keys==2.0.2 # via openedx-events -edx-celeryutils==1.3.0 +edx-celeryutils==1.4.0 # via -r requirements/base.in edx-django-release-util==1.5.0 # via -r requirements/base.in -edx-django-utils==7.4.0 +edx-django-utils==8.0.0 # via # -r requirements/base.in + # edx-auth-backends # edx-drf-extensions # edx-event-bus-kafka # edx-rest-api-client @@ -186,7 +187,7 @@ edx-drf-extensions==10.6.0 # via # -r requirements/base.in # edx-rbac -edx-enterprise-subsidy-client==2.0.3 +edx-enterprise-subsidy-client==2.0.10 # via -r requirements/base.in edx-event-bus-kafka==6.1.0 # via -r requirements/base.in @@ -195,15 +196,17 @@ edx-opaque-keys[django]==3.0.0 # edx-ccx-keys # edx-drf-extensions # openedx-events -edx-rbac==1.10.0 +edx-rbac==2.1.0 # via -r requirements/base.in edx-rest-api-client==6.2.0 # via # -r requirements/base.in # edx-enterprise-subsidy-client -edx-toggles==5.3.0 - # via edx-event-bus-kafka -fastavro==1.10.0 +edx-toggles==5.4.1 + # via + # edx-auth-backends + # edx-event-bus-kafka +fastavro==1.12.0 # via # -r requirements/base.in # confluent-kafka @@ -220,15 +223,15 @@ jinja2==3.1.6 # via # code-annotations # coreschema -jsonfield==3.1.0 +jsonfield==3.2.0 # via edx-celeryutils jsonfield2==4.0.0.post0 # via -r requirements/base.in -jsonschema==4.23.0 +jsonschema==4.25.0 # via drf-spectacular jsonschema-specifications==2025.4.1 # via jsonschema -kombu==5.5.3 +kombu==5.5.4 # via celery markupsafe==3.0.2 # via jinja2 @@ -236,20 +239,20 @@ monotonic==1.6 # via analytics-python mysqlclient==2.2.7 # via -r requirements/base.in -newrelic==10.11.0 - # via edx-django-utils -oauthlib==3.2.2 +oauthlib==3.3.1 # via # requests-oauthlib # social-auth-core openapi-codec==1.3.2 # via django-rest-swagger -openedx-events==10.1.0 +openedx-events==10.4.0 # via # -r requirements/base.in # edx-event-bus-kafka packaging==25.0 - # via drf-yasg + # via + # drf-yasg + # kombu pbr==6.1.1 # via stevedore ply==3.11 @@ -260,7 +263,7 @@ psutil==7.0.0 # via edx-django-utils pycparser==2.22 # via cffi -pygments==2.19.1 +pygments==2.19.2 # via -r requirements/base.in pyjwt[crypto]==2.10.1 # via @@ -271,7 +274,7 @@ pyjwt[crypto]==2.10.1 # social-auth-core pymemcache==4.0.0 # via -r requirements/base.in -pymongo==4.12.1 +pymongo==4.14.0 # via edx-opaque-keys pynacl==1.5.0 # via edx-django-utils @@ -293,13 +296,13 @@ pyyaml==6.0.2 # drf-spectacular # drf-yasg # edx-django-release-util -redis==6.0.0 +redis==6.4.0 # via -r requirements/base.in referencing==0.36.2 # via # jsonschema # jsonschema-specifications -requests==2.32.3 +requests==2.32.4 # via # analytics-python # confluent-kafka @@ -310,7 +313,7 @@ requests==2.32.3 # social-auth-core requests-oauthlib==2.0.0 # via social-auth-core -rpds-py==0.24.0 +rpds-py==0.27.0 # via # jsonschema # referencing @@ -330,7 +333,7 @@ six==1.17.0 # python-dateutil social-auth-app-django==5.4.3 # via edx-auth-backends -social-auth-core==4.6.1 +social-auth-core==4.7.0 # via # edx-auth-backends # social-auth-app-django @@ -343,22 +346,21 @@ stevedore==5.4.1 # edx-opaque-keys text-unidecode==1.3 # via python-slugify -typing-extensions==4.13.2 +typing-extensions==4.14.1 # via + # cattrs # django-countries # edx-opaque-keys # referencing tzdata==2025.2 # via kombu -uritemplate==4.1.1 +uritemplate==4.2.0 # via # coreapi # drf-spectacular # drf-yasg -urllib3==2.2.3 - # via - # -c requirements/common_constraints.txt - # requests +urllib3==2.5.0 + # via requests vine==5.1.0 # via # amqp diff --git a/requirements/common_constraints.txt b/requirements/common_constraints.txt index 134b81d77..99d9bf1bc 100644 --- a/requirements/common_constraints.txt +++ b/requirements/common_constraints.txt @@ -20,13 +20,6 @@ Django<5.0 # See https://github.com/openedx/edx-platform/issues/35126 for more info elasticsearch<7.14.0 -# django-simple-history>3.0.0 adds indexing and causes a lot of migrations to be affected - - # Cause: https://github.com/openedx/edx-lint/issues/458 # This can be unpinned once https://github.com/openedx/edx-lint/issues/459 has been resolved. pip<24.3 - -# Cause: https://github.com/openedx/edx-lint/issues/475 -# This can be unpinned once https://github.com/openedx/edx-lint/issues/476 has been resolved. -urllib3<2.3.0 diff --git a/requirements/dev.txt b/requirements/dev.txt index e60443a3d..74c902290 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -10,13 +10,13 @@ amqp==5.3.1 # kombu analytics-python==1.4.post1 # via -r requirements/validation.txt -asgiref==3.8.1 +asgiref==3.9.1 # via # -r requirements/validation.txt # django # django-cors-headers # django-countries -astroid==3.3.9 +astroid==3.3.11 # via # -r requirements/validation.txt # pylint @@ -40,22 +40,22 @@ billiard==4.2.1 # via # -r requirements/validation.txt # celery -build==1.2.2.post1 +build==1.3.0 # via # -r requirements/pip-tools.txt # pip-tools -cachetools==5.5.2 +cachetools==6.1.0 # via # -r requirements/validation.txt # tox -cattrs==24.1.3 +cattrs==25.1.1 # via -r requirements/validation.txt -celery==5.5.2 +celery==5.5.3 # via # -r requirements/validation.txt # django-celery-results # edx-celeryutils -certifi==2025.4.26 +certifi==2025.8.3 # via # -r requirements/validation.txt # requests @@ -69,11 +69,11 @@ chardet==5.2.0 # -r requirements/validation.txt # diff-cover # tox -charset-normalizer==3.4.2 +charset-normalizer==3.4.3 # via # -r requirements/validation.txt # requests -click==8.1.8 +click==8.2.1 # via # -r requirements/pip-tools.txt # -r requirements/validation.txt @@ -94,7 +94,7 @@ click-log==0.4.0 # via # -r requirements/validation.txt # edx-lint -click-plugins==1.1.1 +click-plugins==1.1.1.2 # via # -r requirements/validation.txt # celery @@ -122,11 +122,11 @@ coreschema==0.0.4 # via # -r requirements/validation.txt # coreapi -coverage[toml]==7.8.0 +coverage[toml]==7.10.3 # via # -r requirements/validation.txt # pytest-cov -cryptography==44.0.3 +cryptography==45.0.6 # via # -r requirements/validation.txt # pyjwt @@ -143,17 +143,17 @@ dictdiffer==0.9.0 # via # -r requirements/validation.txt # pytest-dictsdiff -diff-cover==9.2.4 +diff-cover==9.6.0 # via -r requirements/dev.in dill==0.4.0 # via # -r requirements/validation.txt # pylint -distlib==0.3.9 +distlib==0.4.0 # via # -r requirements/validation.txt # virtualenv -django==4.2.20 +django==4.2.23 # via # -r requirements/validation.txt # django-celery-results @@ -196,7 +196,7 @@ django-crum==0.7.9 # edx-django-utils # edx-rbac # edx-toggles -django-debug-toolbar==5.2.0 +django-debug-toolbar==6.0.0 # via -r requirements/dev.in django-dynamic-fixture==4.0.1 # via -r requirements/validation.txt @@ -215,9 +215,9 @@ django-object-actions==5.0.0 # via -r requirements/validation.txt django-rest-swagger==2.2.0 # via -r requirements/validation.txt -django-simple-history==3.8.0 +django-simple-history==3.10.1 # via -r requirements/validation.txt -django-waffle==4.2.0 +django-waffle==5.0.0 # via # -r requirements/validation.txt # edx-django-utils @@ -225,7 +225,7 @@ django-waffle==4.2.0 # edx-toggles djangoql==0.18.1 # via -r requirements/validation.txt -djangorestframework==3.16.0 +djangorestframework==3.16.1 # via # -r requirements/validation.txt # django-rest-swagger @@ -241,7 +241,7 @@ dnspython==2.7.0 # via # -r requirements/validation.txt # pymongo -docutils==0.21.2 +docutils==0.22 # via # -r requirements/validation.txt # readme-renderer @@ -257,7 +257,7 @@ drf-yasg==1.21.10 # edx-api-doc-tools edx-api-doc-tools==2.1.0 # via -r requirements/validation.txt -edx-auth-backends==4.5.0 +edx-auth-backends==4.6.0 # via -r requirements/validation.txt edx-braze-client==0.2.5 # via -r requirements/validation.txt @@ -265,13 +265,14 @@ edx-ccx-keys==2.0.2 # via # -r requirements/validation.txt # openedx-events -edx-celeryutils==1.3.0 +edx-celeryutils==1.4.0 # via -r requirements/validation.txt edx-django-release-util==1.5.0 # via -r requirements/validation.txt -edx-django-utils==7.4.0 +edx-django-utils==8.0.0 # via # -r requirements/validation.txt + # edx-auth-backends # edx-drf-extensions # edx-event-bus-kafka # edx-rest-api-client @@ -281,7 +282,7 @@ edx-drf-extensions==10.6.0 # via # -r requirements/validation.txt # edx-rbac -edx-enterprise-subsidy-client==2.0.3 +edx-enterprise-subsidy-client==2.0.10 # via -r requirements/validation.txt edx-event-bus-kafka==6.1.0 # via -r requirements/validation.txt @@ -295,23 +296,24 @@ edx-opaque-keys[django]==3.0.0 # edx-ccx-keys # edx-drf-extensions # openedx-events -edx-rbac==1.10.0 +edx-rbac==2.1.0 # via -r requirements/validation.txt edx-rest-api-client==6.2.0 # via # -r requirements/validation.txt # edx-enterprise-subsidy-client -edx-toggles==5.3.0 +edx-toggles==5.4.1 # via # -r requirements/validation.txt + # edx-auth-backends # edx-event-bus-kafka factory-boy==3.3.3 # via -r requirements/validation.txt -faker==37.1.0 +faker==37.5.3 # via # -r requirements/validation.txt # factory-boy -fastavro==1.10.0 +fastavro==1.12.0 # via # -r requirements/validation.txt # confluent-kafka @@ -321,7 +323,7 @@ filelock==3.18.0 # -r requirements/validation.txt # tox # virtualenv -freezegun==1.5.1 +freezegun==1.5.5 # via -r requirements/validation.txt id==1.5.0 # via @@ -356,7 +358,7 @@ jaraco-context==6.0.1 # via # -r requirements/validation.txt # keyring -jaraco-functools==4.1.0 +jaraco-functools==4.2.1 # via # -r requirements/validation.txt # keyring @@ -371,13 +373,13 @@ jinja2==3.1.6 # code-annotations # coreschema # diff-cover -jsonfield==3.1.0 +jsonfield==3.2.0 # via # -r requirements/validation.txt # edx-celeryutils jsonfield2==4.0.0.post0 # via -r requirements/validation.txt -jsonschema==4.23.0 +jsonschema==4.25.0 # via # -r requirements/validation.txt # drf-spectacular @@ -389,17 +391,17 @@ keyring==25.6.0 # via # -r requirements/validation.txt # twine -kombu==5.5.3 +kombu==5.5.4 # via # -r requirements/validation.txt # celery -lxml[html-clean,html_clean]==5.4.0 +lxml[html-clean]==6.0.0 # via # edx-i18n-tools # lxml-html-clean lxml-html-clean==0.4.2 # via lxml -markdown-it-py==3.0.0 +markdown-it-py==4.0.0 # via # -r requirements/validation.txt # rich @@ -426,15 +428,11 @@ more-itertools==10.7.0 # jaraco-functools mysqlclient==2.2.7 # via -r requirements/validation.txt -newrelic==10.11.0 - # via - # -r requirements/validation.txt - # edx-django-utils -nh3==0.2.21 +nh3==0.3.0 # via # -r requirements/validation.txt # readme-renderer -oauthlib==3.2.2 +oauthlib==3.3.1 # via # -r requirements/validation.txt # requests-oauthlib @@ -443,7 +441,7 @@ openapi-codec==1.3.2 # via # -r requirements/validation.txt # django-rest-swagger -openedx-events==10.1.0 +openedx-events==10.4.0 # via # -r requirements/validation.txt # edx-event-bus-kafka @@ -453,6 +451,7 @@ packaging==25.0 # -r requirements/validation.txt # build # drf-yasg + # kombu # pyproject-api # pytest # tox @@ -463,19 +462,20 @@ pbr==6.1.1 # via # -r requirements/validation.txt # stevedore -pip-tools==7.4.1 +pip-tools==7.5.0 # via -r requirements/pip-tools.txt -platformdirs==4.3.7 +platformdirs==4.3.8 # via # -r requirements/validation.txt # pylint # tox # virtualenv -pluggy==1.5.0 +pluggy==1.6.0 # via # -r requirements/validation.txt # diff-cover # pytest + # pytest-cov # tox ply==3.11 # via @@ -491,7 +491,7 @@ psutil==7.0.0 # via # -r requirements/validation.txt # edx-django-utils -pycodestyle==2.13.0 +pycodestyle==2.14.0 # via -r requirements/validation.txt pycparser==2.22 # via @@ -499,10 +499,11 @@ pycparser==2.22 # cffi pydocstyle==6.3.0 # via -r requirements/validation.txt -pygments==2.19.1 +pygments==2.19.2 # via # -r requirements/validation.txt # diff-cover + # pytest # readme-renderer # rich pyjwt[crypto]==2.10.1 @@ -513,7 +514,7 @@ pyjwt[crypto]==2.10.1 # edx-drf-extensions # edx-rest-api-client # social-auth-core -pylint==3.3.7 +pylint==3.3.8 # via # -r requirements/validation.txt # edx-lint @@ -528,14 +529,14 @@ pylint-django==2.6.1 # via # -r requirements/validation.txt # edx-lint -pylint-plugin-utils==0.8.2 +pylint-plugin-utils==0.9.0 # via # -r requirements/validation.txt # pylint-celery # pylint-django pymemcache==4.0.0 # via -r requirements/validation.txt -pymongo==4.12.1 +pymongo==4.14.0 # via # -r requirements/validation.txt # edx-opaque-keys @@ -543,7 +544,7 @@ pynacl==1.5.0 # via # -r requirements/validation.txt # edx-django-utils -pyproject-api==1.9.0 +pyproject-api==1.9.1 # via # -r requirements/validation.txt # tox @@ -552,12 +553,12 @@ pyproject-hooks==1.2.0 # -r requirements/pip-tools.txt # build # pip-tools -pytest==8.3.5 +pytest==8.4.1 # via # -r requirements/validation.txt # pytest-cov # pytest-django -pytest-cov==6.1.1 +pytest-cov==6.2.1 # via -r requirements/validation.txt pytest-dictsdiff==0.5.8 # via -r requirements/validation.txt @@ -593,14 +594,14 @@ readme-renderer==44.0 # via # -r requirements/validation.txt # twine -redis==6.0.0 +redis==6.4.0 # via -r requirements/validation.txt referencing==0.36.2 # via # -r requirements/validation.txt # jsonschema # jsonschema-specifications -requests==2.32.3 +requests==2.32.4 # via # -r requirements/validation.txt # analytics-python @@ -625,11 +626,11 @@ rfc3986==2.0.0 # via # -r requirements/validation.txt # twine -rich==14.0.0 +rich==14.1.0 # via # -r requirements/validation.txt # twine -rpds-py==0.24.0 +rpds-py==0.27.0 # via # -r requirements/validation.txt # jsonschema @@ -658,7 +659,7 @@ six==1.17.0 # edx-lint # edx-rbac # python-dateutil -snowballstemmer==2.2.0 +snowballstemmer==3.0.1 # via # -r requirements/validation.txt # pydocstyle @@ -666,7 +667,7 @@ social-auth-app-django==5.4.3 # via # -r requirements/validation.txt # edx-auth-backends -social-auth-core==4.6.1 +social-auth-core==4.7.0 # via # -r requirements/validation.txt # edx-auth-backends @@ -686,17 +687,18 @@ text-unidecode==1.3 # via # -r requirements/validation.txt # python-slugify -tomlkit==0.13.2 +tomlkit==0.13.3 # via # -r requirements/validation.txt # pylint -tox==4.25.0 +tox==4.28.4 # via -r requirements/validation.txt twine==6.1.0 # via -r requirements/validation.txt -typing-extensions==4.13.2 +typing-extensions==4.14.1 # via # -r requirements/validation.txt + # cattrs # django-countries # edx-opaque-keys # referencing @@ -705,13 +707,13 @@ tzdata==2025.2 # -r requirements/validation.txt # faker # kombu -uritemplate==4.1.1 +uritemplate==4.2.0 # via # -r requirements/validation.txt # coreapi # drf-spectacular # drf-yasg -urllib3==2.2.3 +urllib3==2.5.0 # via # -r requirements/validation.txt # requests @@ -722,7 +724,7 @@ vine==5.1.0 # amqp # celery # kombu -virtualenv==20.30.0 +virtualenv==20.33.1 # via # -r requirements/validation.txt # tox diff --git a/requirements/django.txt b/requirements/django.txt index 9c84bb2a6..c4d956ec3 100644 --- a/requirements/django.txt +++ b/requirements/django.txt @@ -1 +1 @@ -django==4.2.20 +django==4.2.23 diff --git a/requirements/doc.txt b/requirements/doc.txt index 70d205bc2..edd22348a 100644 --- a/requirements/doc.txt +++ b/requirements/doc.txt @@ -14,13 +14,13 @@ amqp==5.3.1 # kombu analytics-python==1.4.post1 # via -r requirements/test.txt -asgiref==3.8.1 +asgiref==3.9.1 # via # -r requirements/test.txt # django # django-cors-headers # django-countries -astroid==3.3.9 +astroid==3.3.11 # via # -r requirements/test.txt # pylint @@ -50,18 +50,18 @@ billiard==4.2.1 # via # -r requirements/test.txt # celery -cachetools==5.5.2 +cachetools==6.1.0 # via # -r requirements/test.txt # tox -cattrs==24.1.3 +cattrs==25.1.1 # via -r requirements/test.txt -celery==5.5.2 +celery==5.5.3 # via # -r requirements/test.txt # django-celery-results # edx-celeryutils -certifi==2025.4.26 +certifi==2025.8.3 # via # -r requirements/test.txt # requests @@ -74,11 +74,11 @@ chardet==5.2.0 # via # -r requirements/test.txt # tox -charset-normalizer==3.4.2 +charset-normalizer==3.4.3 # via # -r requirements/test.txt # requests -click==8.1.8 +click==8.2.1 # via # -r requirements/test.txt # celery @@ -97,7 +97,7 @@ click-log==0.4.0 # via # -r requirements/test.txt # edx-lint -click-plugins==1.1.1 +click-plugins==1.1.1.2 # via # -r requirements/test.txt # celery @@ -127,11 +127,11 @@ coreschema==0.0.4 # via # -r requirements/test.txt # coreapi -coverage[toml]==7.8.0 +coverage[toml]==7.10.3 # via # -r requirements/test.txt # pytest-cov -cryptography==44.0.3 +cryptography==45.0.6 # via # -r requirements/test.txt # pyjwt @@ -151,11 +151,11 @@ dill==0.4.0 # via # -r requirements/test.txt # pylint -distlib==0.3.9 +distlib==0.4.0 # via # -r requirements/test.txt # virtualenv -django==4.2.20 +django==4.2.23 # via # -c requirements/common_constraints.txt # -r requirements/test.txt @@ -214,9 +214,9 @@ django-object-actions==5.0.0 # via -r requirements/test.txt django-rest-swagger==2.2.0 # via -r requirements/test.txt -django-simple-history==3.8.0 +django-simple-history==3.10.1 # via -r requirements/test.txt -django-waffle==4.2.0 +django-waffle==5.0.0 # via # -r requirements/test.txt # edx-django-utils @@ -224,7 +224,7 @@ django-waffle==4.2.0 # edx-toggles djangoql==0.18.1 # via -r requirements/test.txt -djangorestframework==3.16.0 +djangorestframework==3.16.1 # via # -r requirements/test.txt # django-rest-swagger @@ -240,7 +240,7 @@ dnspython==2.7.0 # via # -r requirements/test.txt # pymongo -doc8==1.1.2 +doc8==2.0.0 # via -r requirements/doc.in docutils==0.21.2 # via @@ -261,7 +261,7 @@ drf-yasg==1.21.10 # edx-api-doc-tools edx-api-doc-tools==2.1.0 # via -r requirements/test.txt -edx-auth-backends==4.5.0 +edx-auth-backends==4.6.0 # via -r requirements/test.txt edx-braze-client==0.2.5 # via @@ -271,13 +271,14 @@ edx-ccx-keys==2.0.2 # via # -r requirements/test.txt # openedx-events -edx-celeryutils==1.3.0 +edx-celeryutils==1.4.0 # via -r requirements/test.txt edx-django-release-util==1.5.0 # via -r requirements/test.txt -edx-django-utils==7.4.0 +edx-django-utils==8.0.0 # via # -r requirements/test.txt + # edx-auth-backends # edx-drf-extensions # edx-event-bus-kafka # edx-rest-api-client @@ -287,7 +288,7 @@ edx-drf-extensions==10.6.0 # via # -r requirements/test.txt # edx-rbac -edx-enterprise-subsidy-client==2.0.3 +edx-enterprise-subsidy-client==2.0.10 # via -r requirements/test.txt edx-event-bus-kafka==6.1.0 # via -r requirements/test.txt @@ -299,23 +300,24 @@ edx-opaque-keys[django]==3.0.0 # edx-ccx-keys # edx-drf-extensions # openedx-events -edx-rbac==1.10.0 +edx-rbac==2.1.0 # via -r requirements/test.txt edx-rest-api-client==6.2.0 # via # -r requirements/test.txt # edx-enterprise-subsidy-client -edx-toggles==5.3.0 +edx-toggles==5.4.1 # via # -r requirements/test.txt + # edx-auth-backends # edx-event-bus-kafka factory-boy==3.3.3 # via -r requirements/test.txt -faker==37.1.0 +faker==37.5.3 # via # -r requirements/test.txt # factory-boy -fastavro==1.10.0 +fastavro==1.12.0 # via # -r requirements/test.txt # confluent-kafka @@ -325,7 +327,7 @@ filelock==3.18.0 # -r requirements/test.txt # tox # virtualenv -freezegun==1.5.1 +freezegun==1.5.5 # via -r requirements/test.txt idna==3.10 # via @@ -356,13 +358,13 @@ jinja2==3.1.6 # code-annotations # coreschema # sphinx -jsonfield==3.1.0 +jsonfield==3.2.0 # via # -r requirements/test.txt # edx-celeryutils jsonfield2==4.0.0.post0 # via -r requirements/test.txt -jsonschema==4.23.0 +jsonschema==4.25.0 # via # -r requirements/test.txt # drf-spectacular @@ -370,7 +372,7 @@ jsonschema-specifications==2025.4.1 # via # -r requirements/test.txt # jsonschema -kombu==5.5.3 +kombu==5.5.4 # via # -r requirements/test.txt # celery @@ -388,13 +390,9 @@ monotonic==1.6 # analytics-python mysqlclient==2.2.7 # via -r requirements/test.txt -newrelic==10.11.0 - # via - # -r requirements/test.txt - # edx-django-utils -nh3==0.2.21 +nh3==0.3.0 # via readme-renderer -oauthlib==3.2.2 +oauthlib==3.3.1 # via # -r requirements/test.txt # requests-oauthlib @@ -403,7 +401,7 @@ openapi-codec==1.3.2 # via # -r requirements/test.txt # django-rest-swagger -openedx-events==10.1.0 +openedx-events==10.4.0 # via # -r requirements/test.txt # edx-event-bus-kafka @@ -411,6 +409,7 @@ packaging==25.0 # via # -r requirements/test.txt # drf-yasg + # kombu # pydata-sphinx-theme # pyproject-api # pytest @@ -420,16 +419,17 @@ pbr==6.1.1 # via # -r requirements/test.txt # stevedore -platformdirs==4.3.7 +platformdirs==4.3.8 # via # -r requirements/test.txt # pylint # tox # virtualenv -pluggy==1.5.0 +pluggy==1.6.0 # via # -r requirements/test.txt # pytest + # pytest-cov # tox ply==3.11 # via @@ -449,12 +449,13 @@ pycparser==2.22 # cffi pydata-sphinx-theme==0.15.4 # via sphinx-book-theme -pygments==2.19.1 +pygments==2.19.2 # via # -r requirements/test.txt # accessible-pygments # doc8 # pydata-sphinx-theme + # pytest # readme-renderer # sphinx pyjwt[crypto]==2.10.1 @@ -465,7 +466,7 @@ pyjwt[crypto]==2.10.1 # edx-drf-extensions # edx-rest-api-client # social-auth-core -pylint==3.3.7 +pylint==3.3.8 # via # -r requirements/test.txt # edx-lint @@ -480,14 +481,14 @@ pylint-django==2.6.1 # via # -r requirements/test.txt # edx-lint -pylint-plugin-utils==0.8.2 +pylint-plugin-utils==0.9.0 # via # -r requirements/test.txt # pylint-celery # pylint-django pymemcache==4.0.0 # via -r requirements/test.txt -pymongo==4.12.1 +pymongo==4.14.0 # via # -r requirements/test.txt # edx-opaque-keys @@ -495,16 +496,16 @@ pynacl==1.5.0 # via # -r requirements/test.txt # edx-django-utils -pyproject-api==1.9.0 +pyproject-api==1.9.1 # via # -r requirements/test.txt # tox -pytest==8.3.5 +pytest==8.4.1 # via # -r requirements/test.txt # pytest-cov # pytest-django -pytest-cov==6.1.1 +pytest-cov==6.2.1 # via -r requirements/test.txt pytest-dictsdiff==0.5.8 # via -r requirements/test.txt @@ -537,14 +538,14 @@ pyyaml==6.0.2 # edx-django-release-util readme-renderer==44.0 # via -r requirements/doc.in -redis==6.0.0 +redis==6.4.0 # via -r requirements/test.txt referencing==0.36.2 # via # -r requirements/test.txt # jsonschema # jsonschema-specifications -requests==2.32.3 +requests==2.32.4 # via # -r requirements/test.txt # analytics-python @@ -563,7 +564,7 @@ restructuredtext-lint==1.4.0 # via doc8 roman-numerals-py==3.1.0 # via sphinx -rpds-py==0.24.0 +rpds-py==0.27.0 # via # -r requirements/test.txt # jsonschema @@ -588,13 +589,13 @@ six==1.17.0 # edx-lint # edx-rbac # python-dateutil -snowballstemmer==2.2.0 +snowballstemmer==3.0.1 # via sphinx social-auth-app-django==5.4.3 # via # -r requirements/test.txt # edx-auth-backends -social-auth-core==4.6.1 +social-auth-core==4.7.0 # via # -r requirements/test.txt # edx-auth-backends @@ -635,16 +636,17 @@ text-unidecode==1.3 # via # -r requirements/test.txt # python-slugify -tomlkit==0.13.2 +tomlkit==0.13.3 # via # -r requirements/test.txt # pylint -tox==4.25.0 +tox==4.28.4 # via -r requirements/test.txt -typing-extensions==4.13.2 +typing-extensions==4.14.1 # via # -r requirements/test.txt # beautifulsoup4 + # cattrs # django-countries # edx-opaque-keys # pydata-sphinx-theme @@ -654,15 +656,14 @@ tzdata==2025.2 # -r requirements/test.txt # faker # kombu -uritemplate==4.1.1 +uritemplate==4.2.0 # via # -r requirements/test.txt # coreapi # drf-spectacular # drf-yasg -urllib3==2.2.3 +urllib3==2.5.0 # via - # -c requirements/common_constraints.txt # -r requirements/test.txt # requests vine==5.1.0 @@ -671,7 +672,7 @@ vine==5.1.0 # amqp # celery # kombu -virtualenv==20.30.0 +virtualenv==20.33.1 # via # -r requirements/test.txt # tox diff --git a/requirements/pip-tools.txt b/requirements/pip-tools.txt index 441fb714d..bfdc0512f 100644 --- a/requirements/pip-tools.txt +++ b/requirements/pip-tools.txt @@ -4,13 +4,13 @@ # # make upgrade # -build==1.2.2.post1 +build==1.3.0 # via pip-tools -click==8.1.8 +click==8.2.1 # via pip-tools packaging==25.0 # via build -pip-tools==7.4.1 +pip-tools==7.5.0 # via -r requirements/pip-tools.in pyproject-hooks==1.2.0 # via diff --git a/requirements/pip.txt b/requirements/pip.txt index 9781c4fc1..476adfba8 100644 --- a/requirements/pip.txt +++ b/requirements/pip.txt @@ -10,7 +10,7 @@ wheel==0.45.1 # The following packages are considered to be unsafe in a requirements file: pip==24.2 # via - # -c /home/runner/work/enterprise-access/enterprise-access/requirements/common_constraints.txt + # -c requirements/common_constraints.txt # -r requirements/pip.in -setuptools==80.3.1 +setuptools==80.9.0 # via -r requirements/pip.in diff --git a/requirements/production.txt b/requirements/production.txt index 1614dc94a..8b12a0d8c 100644 --- a/requirements/production.txt +++ b/requirements/production.txt @@ -10,7 +10,7 @@ amqp==5.3.1 # kombu analytics-python==1.4.post1 # via -r requirements/base.txt -asgiref==3.8.1 +asgiref==3.9.1 # via # -r requirements/base.txt # django @@ -35,14 +35,14 @@ billiard==4.2.1 # via # -r requirements/base.txt # celery -cattrs==24.1.3 +cattrs==25.1.1 # via -r requirements/base.txt -celery==5.5.2 +celery==5.5.3 # via # -r requirements/base.txt # django-celery-results # edx-celeryutils -certifi==2025.4.26 +certifi==2025.8.3 # via # -r requirements/base.txt # requests @@ -51,11 +51,11 @@ cffi==1.17.1 # -r requirements/base.txt # cryptography # pynacl -charset-normalizer==3.4.2 +charset-normalizer==3.4.3 # via # -r requirements/base.txt # requests -click==8.1.8 +click==8.2.1 # via # -r requirements/base.txt # celery @@ -68,7 +68,7 @@ click-didyoumean==0.3.1 # via # -r requirements/base.txt # celery -click-plugins==1.1.1 +click-plugins==1.1.1.2 # via # -r requirements/base.txt # celery @@ -91,7 +91,7 @@ coreschema==0.0.4 # via # -r requirements/base.txt # coreapi -cryptography==44.0.3 +cryptography==45.0.6 # via # -r requirements/base.txt # pyjwt @@ -101,7 +101,7 @@ defusedxml==0.7.1 # -r requirements/base.txt # python3-openid # social-auth-core -django==4.2.20 +django==4.2.23 # via # -r requirements/base.txt # django-celery-results @@ -157,9 +157,9 @@ django-object-actions==5.0.0 # via -r requirements/base.txt django-rest-swagger==2.2.0 # via -r requirements/base.txt -django-simple-history==3.8.0 +django-simple-history==3.10.1 # via -r requirements/base.txt -django-waffle==4.2.0 +django-waffle==5.0.0 # via # -r requirements/base.txt # edx-django-utils @@ -167,7 +167,7 @@ django-waffle==4.2.0 # edx-toggles djangoql==0.18.1 # via -r requirements/base.txt -djangorestframework==3.16.0 +djangorestframework==3.16.1 # via # -r requirements/base.txt # django-rest-swagger @@ -195,7 +195,7 @@ drf-yasg==1.21.10 # edx-api-doc-tools edx-api-doc-tools==2.1.0 # via -r requirements/base.txt -edx-auth-backends==4.5.0 +edx-auth-backends==4.6.0 # via -r requirements/base.txt edx-braze-client==0.2.5 # via -r requirements/base.txt @@ -203,13 +203,14 @@ edx-ccx-keys==2.0.2 # via # -r requirements/base.txt # openedx-events -edx-celeryutils==1.3.0 +edx-celeryutils==1.4.0 # via -r requirements/base.txt edx-django-release-util==1.5.0 # via -r requirements/base.txt -edx-django-utils==7.4.0 +edx-django-utils==8.0.0 # via # -r requirements/base.txt + # edx-auth-backends # edx-drf-extensions # edx-event-bus-kafka # edx-rest-api-client @@ -219,7 +220,7 @@ edx-drf-extensions==10.6.0 # via # -r requirements/base.txt # edx-rbac -edx-enterprise-subsidy-client==2.0.3 +edx-enterprise-subsidy-client==2.0.10 # via -r requirements/base.txt edx-event-bus-kafka==6.1.0 # via -r requirements/base.txt @@ -229,24 +230,25 @@ edx-opaque-keys[django]==3.0.0 # edx-ccx-keys # edx-drf-extensions # openedx-events -edx-rbac==1.10.0 +edx-rbac==2.1.0 # via -r requirements/base.txt edx-rest-api-client==6.2.0 # via # -r requirements/base.txt # edx-enterprise-subsidy-client -edx-toggles==5.3.0 +edx-toggles==5.4.1 # via # -r requirements/base.txt + # edx-auth-backends # edx-event-bus-kafka -fastavro==1.10.0 +fastavro==1.12.0 # via # -r requirements/base.txt # confluent-kafka # openedx-events -gevent==25.4.2 +gevent==25.5.1 # via -r requirements/production.in -greenlet==3.2.1 +greenlet==3.2.4 # via gevent gunicorn==23.0.0 # via -r requirements/production.in @@ -268,13 +270,13 @@ jinja2==3.1.6 # -r requirements/base.txt # code-annotations # coreschema -jsonfield==3.1.0 +jsonfield==3.2.0 # via # -r requirements/base.txt # edx-celeryutils jsonfield2==4.0.0.post0 # via -r requirements/base.txt -jsonschema==4.23.0 +jsonschema==4.25.0 # via # -r requirements/base.txt # drf-spectacular @@ -282,7 +284,7 @@ jsonschema-specifications==2025.4.1 # via # -r requirements/base.txt # jsonschema -kombu==5.5.3 +kombu==5.5.4 # via # -r requirements/base.txt # celery @@ -298,11 +300,7 @@ mysqlclient==2.2.7 # via # -r requirements/base.txt # -r requirements/production.in -newrelic==10.11.0 - # via - # -r requirements/base.txt - # edx-django-utils -oauthlib==3.2.2 +oauthlib==3.3.1 # via # -r requirements/base.txt # requests-oauthlib @@ -311,7 +309,7 @@ openapi-codec==1.3.2 # via # -r requirements/base.txt # django-rest-swagger -openedx-events==10.1.0 +openedx-events==10.4.0 # via # -r requirements/base.txt # edx-event-bus-kafka @@ -320,6 +318,7 @@ packaging==25.0 # -r requirements/base.txt # drf-yasg # gunicorn + # kombu pbr==6.1.1 # via # -r requirements/base.txt @@ -340,7 +339,7 @@ pycparser==2.22 # via # -r requirements/base.txt # cffi -pygments==2.19.1 +pygments==2.19.2 # via -r requirements/base.txt pyjwt[crypto]==2.10.1 # via @@ -352,7 +351,7 @@ pyjwt[crypto]==2.10.1 # social-auth-core pymemcache==4.0.0 # via -r requirements/base.txt -pymongo==4.12.1 +pymongo==4.14.0 # via # -r requirements/base.txt # edx-opaque-keys @@ -387,14 +386,14 @@ pyyaml==6.0.2 # drf-spectacular # drf-yasg # edx-django-release-util -redis==6.0.0 +redis==6.4.0 # via -r requirements/base.txt referencing==0.36.2 # via # -r requirements/base.txt # jsonschema # jsonschema-specifications -requests==2.32.3 +requests==2.32.4 # via # -r requirements/base.txt # analytics-python @@ -408,7 +407,7 @@ requests-oauthlib==2.0.0 # via # -r requirements/base.txt # social-auth-core -rpds-py==0.24.0 +rpds-py==0.27.0 # via # -r requirements/base.txt # jsonschema @@ -436,7 +435,7 @@ social-auth-app-django==5.4.3 # via # -r requirements/base.txt # edx-auth-backends -social-auth-core==4.6.1 +social-auth-core==4.7.0 # via # -r requirements/base.txt # edx-auth-backends @@ -455,9 +454,10 @@ text-unidecode==1.3 # via # -r requirements/base.txt # python-slugify -typing-extensions==4.13.2 +typing-extensions==4.14.1 # via # -r requirements/base.txt + # cattrs # django-countries # edx-opaque-keys # referencing @@ -465,13 +465,13 @@ tzdata==2025.2 # via # -r requirements/base.txt # kombu -uritemplate==4.1.1 +uritemplate==4.2.0 # via # -r requirements/base.txt # coreapi # drf-spectacular # drf-yasg -urllib3==2.2.3 +urllib3==2.5.0 # via # -r requirements/base.txt # requests @@ -485,7 +485,7 @@ wcwidth==0.2.13 # via # -r requirements/base.txt # prompt-toolkit -zope-event==5.0 +zope-event==5.1.1 # via gevent zope-interface==7.2 # via gevent diff --git a/requirements/quality.txt b/requirements/quality.txt index 4c7f8caea..09856df26 100644 --- a/requirements/quality.txt +++ b/requirements/quality.txt @@ -10,13 +10,13 @@ amqp==5.3.1 # kombu analytics-python==1.4.post1 # via -r requirements/test.txt -asgiref==3.8.1 +asgiref==3.9.1 # via # -r requirements/test.txt # django # django-cors-headers # django-countries -astroid==3.3.9 +astroid==3.3.11 # via # -r requirements/test.txt # pylint @@ -40,18 +40,18 @@ billiard==4.2.1 # via # -r requirements/test.txt # celery -cachetools==5.5.2 +cachetools==6.1.0 # via # -r requirements/test.txt # tox -cattrs==24.1.3 +cattrs==25.1.1 # via -r requirements/test.txt -celery==5.5.2 +celery==5.5.3 # via # -r requirements/test.txt # django-celery-results # edx-celeryutils -certifi==2025.4.26 +certifi==2025.8.3 # via # -r requirements/test.txt # requests @@ -64,11 +64,11 @@ chardet==5.2.0 # via # -r requirements/test.txt # tox -charset-normalizer==3.4.2 +charset-normalizer==3.4.3 # via # -r requirements/test.txt # requests -click==8.1.8 +click==8.2.1 # via # -r requirements/test.txt # celery @@ -87,7 +87,7 @@ click-log==0.4.0 # via # -r requirements/test.txt # edx-lint -click-plugins==1.1.1 +click-plugins==1.1.1.2 # via # -r requirements/test.txt # celery @@ -117,11 +117,11 @@ coreschema==0.0.4 # via # -r requirements/test.txt # coreapi -coverage[toml]==7.8.0 +coverage[toml]==7.10.3 # via # -r requirements/test.txt # pytest-cov -cryptography==44.0.3 +cryptography==45.0.6 # via # -r requirements/test.txt # pyjwt @@ -142,11 +142,11 @@ dill==0.4.0 # via # -r requirements/test.txt # pylint -distlib==0.3.9 +distlib==0.4.0 # via # -r requirements/test.txt # virtualenv -django==4.2.20 +django==4.2.23 # via # -c requirements/common_constraints.txt # -r requirements/test.txt @@ -205,9 +205,9 @@ django-object-actions==5.0.0 # via -r requirements/test.txt django-rest-swagger==2.2.0 # via -r requirements/test.txt -django-simple-history==3.8.0 +django-simple-history==3.10.1 # via -r requirements/test.txt -django-waffle==4.2.0 +django-waffle==5.0.0 # via # -r requirements/test.txt # edx-django-utils @@ -215,7 +215,7 @@ django-waffle==4.2.0 # edx-toggles djangoql==0.18.1 # via -r requirements/test.txt -djangorestframework==3.16.0 +djangorestframework==3.16.1 # via # -r requirements/test.txt # django-rest-swagger @@ -231,7 +231,7 @@ dnspython==2.7.0 # via # -r requirements/test.txt # pymongo -docutils==0.21.2 +docutils==0.22 # via readme-renderer drf-jwt==1.19.2 # via @@ -245,7 +245,7 @@ drf-yasg==1.21.10 # edx-api-doc-tools edx-api-doc-tools==2.1.0 # via -r requirements/test.txt -edx-auth-backends==4.5.0 +edx-auth-backends==4.6.0 # via -r requirements/test.txt edx-braze-client==0.2.5 # via @@ -255,13 +255,14 @@ edx-ccx-keys==2.0.2 # via # -r requirements/test.txt # openedx-events -edx-celeryutils==1.3.0 +edx-celeryutils==1.4.0 # via -r requirements/test.txt edx-django-release-util==1.5.0 # via -r requirements/test.txt -edx-django-utils==7.4.0 +edx-django-utils==8.0.0 # via # -r requirements/test.txt + # edx-auth-backends # edx-drf-extensions # edx-event-bus-kafka # edx-rest-api-client @@ -271,7 +272,7 @@ edx-drf-extensions==10.6.0 # via # -r requirements/test.txt # edx-rbac -edx-enterprise-subsidy-client==2.0.3 +edx-enterprise-subsidy-client==2.0.10 # via -r requirements/test.txt edx-event-bus-kafka==6.1.0 # via -r requirements/test.txt @@ -285,23 +286,24 @@ edx-opaque-keys[django]==3.0.0 # edx-ccx-keys # edx-drf-extensions # openedx-events -edx-rbac==1.10.0 +edx-rbac==2.1.0 # via -r requirements/test.txt edx-rest-api-client==6.2.0 # via # -r requirements/test.txt # edx-enterprise-subsidy-client -edx-toggles==5.3.0 +edx-toggles==5.4.1 # via # -r requirements/test.txt + # edx-auth-backends # edx-event-bus-kafka factory-boy==3.3.3 # via -r requirements/test.txt -faker==37.1.0 +faker==37.5.3 # via # -r requirements/test.txt # factory-boy -fastavro==1.10.0 +fastavro==1.12.0 # via # -r requirements/test.txt # confluent-kafka @@ -311,7 +313,7 @@ filelock==3.18.0 # -r requirements/test.txt # tox # virtualenv -freezegun==1.5.1 +freezegun==1.5.5 # via -r requirements/test.txt id==1.5.0 # via twine @@ -341,7 +343,7 @@ jaraco-classes==3.4.0 # via keyring jaraco-context==6.0.1 # via keyring -jaraco-functools==4.1.0 +jaraco-functools==4.2.1 # via keyring jeepney==0.9.0 # via @@ -352,13 +354,13 @@ jinja2==3.1.6 # -r requirements/test.txt # code-annotations # coreschema -jsonfield==3.1.0 +jsonfield==3.2.0 # via # -r requirements/test.txt # edx-celeryutils jsonfield2==4.0.0.post0 # via -r requirements/test.txt -jsonschema==4.23.0 +jsonschema==4.25.0 # via # -r requirements/test.txt # drf-spectacular @@ -368,11 +370,11 @@ jsonschema-specifications==2025.4.1 # jsonschema keyring==25.6.0 # via twine -kombu==5.5.3 +kombu==5.5.4 # via # -r requirements/test.txt # celery -markdown-it-py==3.0.0 +markdown-it-py==4.0.0 # via rich markupsafe==3.0.2 # via @@ -394,13 +396,9 @@ more-itertools==10.7.0 # jaraco-functools mysqlclient==2.2.7 # via -r requirements/test.txt -newrelic==10.11.0 - # via - # -r requirements/test.txt - # edx-django-utils -nh3==0.2.21 +nh3==0.3.0 # via readme-renderer -oauthlib==3.2.2 +oauthlib==3.3.1 # via # -r requirements/test.txt # requests-oauthlib @@ -409,7 +407,7 @@ openapi-codec==1.3.2 # via # -r requirements/test.txt # django-rest-swagger -openedx-events==10.1.0 +openedx-events==10.4.0 # via # -r requirements/test.txt # edx-event-bus-kafka @@ -417,6 +415,7 @@ packaging==25.0 # via # -r requirements/test.txt # drf-yasg + # kombu # pyproject-api # pytest # tox @@ -425,16 +424,17 @@ pbr==6.1.1 # via # -r requirements/test.txt # stevedore -platformdirs==4.3.7 +platformdirs==4.3.8 # via # -r requirements/test.txt # pylint # tox # virtualenv -pluggy==1.5.0 +pluggy==1.6.0 # via # -r requirements/test.txt # pytest + # pytest-cov # tox ply==3.11 # via @@ -448,7 +448,7 @@ psutil==7.0.0 # via # -r requirements/test.txt # edx-django-utils -pycodestyle==2.13.0 +pycodestyle==2.14.0 # via -r requirements/quality.in pycparser==2.22 # via @@ -456,9 +456,10 @@ pycparser==2.22 # cffi pydocstyle==6.3.0 # via -r requirements/quality.in -pygments==2.19.1 +pygments==2.19.2 # via # -r requirements/test.txt + # pytest # readme-renderer # rich pyjwt[crypto]==2.10.1 @@ -469,7 +470,7 @@ pyjwt[crypto]==2.10.1 # edx-drf-extensions # edx-rest-api-client # social-auth-core -pylint==3.3.7 +pylint==3.3.8 # via # -r requirements/test.txt # edx-lint @@ -484,14 +485,14 @@ pylint-django==2.6.1 # via # -r requirements/test.txt # edx-lint -pylint-plugin-utils==0.8.2 +pylint-plugin-utils==0.9.0 # via # -r requirements/test.txt # pylint-celery # pylint-django pymemcache==4.0.0 # via -r requirements/test.txt -pymongo==4.12.1 +pymongo==4.14.0 # via # -r requirements/test.txt # edx-opaque-keys @@ -499,16 +500,16 @@ pynacl==1.5.0 # via # -r requirements/test.txt # edx-django-utils -pyproject-api==1.9.0 +pyproject-api==1.9.1 # via # -r requirements/test.txt # tox -pytest==8.3.5 +pytest==8.4.1 # via # -r requirements/test.txt # pytest-cov # pytest-django -pytest-cov==6.1.1 +pytest-cov==6.2.1 # via -r requirements/test.txt pytest-dictsdiff==0.5.8 # via -r requirements/test.txt @@ -541,14 +542,14 @@ pyyaml==6.0.2 # edx-django-release-util readme-renderer==44.0 # via twine -redis==6.0.0 +redis==6.4.0 # via -r requirements/test.txt referencing==0.36.2 # via # -r requirements/test.txt # jsonschema # jsonschema-specifications -requests==2.32.3 +requests==2.32.4 # via # -r requirements/test.txt # analytics-python @@ -569,9 +570,9 @@ requests-toolbelt==1.0.0 # via twine rfc3986==2.0.0 # via twine -rich==14.0.0 +rich==14.1.0 # via twine -rpds-py==0.24.0 +rpds-py==0.27.0 # via # -r requirements/test.txt # jsonschema @@ -598,13 +599,13 @@ six==1.17.0 # edx-lint # edx-rbac # python-dateutil -snowballstemmer==2.2.0 +snowballstemmer==3.0.1 # via pydocstyle social-auth-app-django==5.4.3 # via # -r requirements/test.txt # edx-auth-backends -social-auth-core==4.6.1 +social-auth-core==4.7.0 # via # -r requirements/test.txt # edx-auth-backends @@ -623,17 +624,18 @@ text-unidecode==1.3 # via # -r requirements/test.txt # python-slugify -tomlkit==0.13.2 +tomlkit==0.13.3 # via # -r requirements/test.txt # pylint -tox==4.25.0 +tox==4.28.4 # via -r requirements/test.txt twine==6.1.0 # via -r requirements/quality.in -typing-extensions==4.13.2 +typing-extensions==4.14.1 # via # -r requirements/test.txt + # cattrs # django-countries # edx-opaque-keys # referencing @@ -642,15 +644,14 @@ tzdata==2025.2 # -r requirements/test.txt # faker # kombu -uritemplate==4.1.1 +uritemplate==4.2.0 # via # -r requirements/test.txt # coreapi # drf-spectacular # drf-yasg -urllib3==2.2.3 +urllib3==2.5.0 # via - # -c requirements/common_constraints.txt # -r requirements/test.txt # requests # twine @@ -660,7 +661,7 @@ vine==5.1.0 # amqp # celery # kombu -virtualenv==20.30.0 +virtualenv==20.33.1 # via # -r requirements/test.txt # tox diff --git a/requirements/test.txt b/requirements/test.txt index b72a6f57c..a57208195 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -10,13 +10,13 @@ amqp==5.3.1 # kombu analytics-python==1.4.post1 # via -r requirements/base.txt -asgiref==3.8.1 +asgiref==3.9.1 # via # -r requirements/base.txt # django # django-cors-headers # django-countries -astroid==3.3.9 +astroid==3.3.11 # via # pylint # pylint-celery @@ -39,16 +39,16 @@ billiard==4.2.1 # via # -r requirements/base.txt # celery -cachetools==5.5.2 +cachetools==6.1.0 # via tox -cattrs==24.1.3 +cattrs==25.1.1 # via -r requirements/base.txt -celery==5.5.2 +celery==5.5.3 # via # -r requirements/base.txt # django-celery-results # edx-celeryutils -certifi==2025.4.26 +certifi==2025.8.3 # via # -r requirements/base.txt # requests @@ -59,11 +59,11 @@ cffi==1.17.1 # pynacl chardet==5.2.0 # via tox -charset-normalizer==3.4.2 +charset-normalizer==3.4.3 # via # -r requirements/base.txt # requests -click==8.1.8 +click==8.2.1 # via # -r requirements/base.txt # celery @@ -80,7 +80,7 @@ click-didyoumean==0.3.1 # celery click-log==0.4.0 # via edx-lint -click-plugins==1.1.1 +click-plugins==1.1.1.2 # via # -r requirements/base.txt # celery @@ -109,11 +109,11 @@ coreschema==0.0.4 # via # -r requirements/base.txt # coreapi -coverage[toml]==7.8.0 +coverage[toml]==7.10.3 # via # -r requirements/test.in # pytest-cov -cryptography==44.0.3 +cryptography==45.0.6 # via # -r requirements/base.txt # pyjwt @@ -129,7 +129,7 @@ dictdiffer==0.9.0 # via pytest-dictsdiff dill==0.4.0 # via pylint -distlib==0.3.9 +distlib==0.4.0 # via virtualenv # via # -c requirements/common_constraints.txt @@ -189,9 +189,9 @@ django-object-actions==5.0.0 # via -r requirements/base.txt django-rest-swagger==2.2.0 # via -r requirements/base.txt -django-simple-history==3.8.0 +django-simple-history==3.10.1 # via -r requirements/base.txt -django-waffle==4.2.0 +django-waffle==5.0.0 # via # -r requirements/base.txt # edx-django-utils @@ -199,7 +199,7 @@ django-waffle==4.2.0 # edx-toggles djangoql==0.18.1 # via -r requirements/base.txt -djangorestframework==3.16.0 +djangorestframework==3.16.1 # via # -r requirements/base.txt # django-rest-swagger @@ -227,7 +227,7 @@ drf-yasg==1.21.10 # edx-api-doc-tools edx-api-doc-tools==2.1.0 # via -r requirements/base.txt -edx-auth-backends==4.5.0 +edx-auth-backends==4.6.0 # via -r requirements/base.txt edx-braze-client==0.2.5 # via @@ -237,13 +237,14 @@ edx-ccx-keys==2.0.2 # via # -r requirements/base.txt # openedx-events -edx-celeryutils==1.3.0 +edx-celeryutils==1.4.0 # via -r requirements/base.txt edx-django-release-util==1.5.0 # via -r requirements/base.txt -edx-django-utils==7.4.0 +edx-django-utils==8.0.0 # via # -r requirements/base.txt + # edx-auth-backends # edx-drf-extensions # edx-event-bus-kafka # edx-rest-api-client @@ -253,7 +254,7 @@ edx-drf-extensions==10.6.0 # via # -r requirements/base.txt # edx-rbac -edx-enterprise-subsidy-client==2.0.3 +edx-enterprise-subsidy-client==2.0.10 # via -r requirements/base.txt edx-event-bus-kafka==6.1.0 # via -r requirements/base.txt @@ -265,21 +266,22 @@ edx-opaque-keys[django]==3.0.0 # edx-ccx-keys # edx-drf-extensions # openedx-events -edx-rbac==1.10.0 +edx-rbac==2.1.0 # via -r requirements/base.txt edx-rest-api-client==6.2.0 # via # -r requirements/base.txt # edx-enterprise-subsidy-client -edx-toggles==5.3.0 +edx-toggles==5.4.1 # via # -r requirements/base.txt + # edx-auth-backends # edx-event-bus-kafka factory-boy==3.3.3 # via -r requirements/test.in -faker==37.1.0 +faker==37.5.3 # via factory-boy -fastavro==1.10.0 +fastavro==1.12.0 # via # -r requirements/base.txt # confluent-kafka @@ -288,7 +290,7 @@ filelock==3.18.0 # via # tox # virtualenv -freezegun==1.5.1 +freezegun==1.5.5 # via -r requirements/test.in idna==3.10 # via @@ -312,13 +314,13 @@ jinja2==3.1.6 # -r requirements/base.txt # code-annotations # coreschema -jsonfield==3.1.0 +jsonfield==3.2.0 # via # -r requirements/base.txt # edx-celeryutils jsonfield2==4.0.0.post0 # via -r requirements/base.txt -jsonschema==4.23.0 +jsonschema==4.25.0 # via # -r requirements/base.txt # drf-spectacular @@ -326,7 +328,7 @@ jsonschema-specifications==2025.4.1 # via # -r requirements/base.txt # jsonschema -kombu==5.5.3 +kombu==5.5.4 # via # -r requirements/base.txt # celery @@ -342,11 +344,7 @@ monotonic==1.6 # analytics-python mysqlclient==2.2.7 # via -r requirements/base.txt -newrelic==10.11.0 - # via - # -r requirements/base.txt - # edx-django-utils -oauthlib==3.2.2 +oauthlib==3.3.1 # via # -r requirements/base.txt # requests-oauthlib @@ -355,7 +353,7 @@ openapi-codec==1.3.2 # via # -r requirements/base.txt # django-rest-swagger -openedx-events==10.1.0 +openedx-events==10.4.0 # via # -r requirements/base.txt # edx-event-bus-kafka @@ -363,6 +361,7 @@ packaging==25.0 # via # -r requirements/base.txt # drf-yasg + # kombu # pyproject-api # pytest # tox @@ -370,14 +369,15 @@ pbr==6.1.1 # via # -r requirements/base.txt # stevedore -platformdirs==4.3.7 +platformdirs==4.3.8 # via # pylint # tox # virtualenv -pluggy==1.5.0 +pluggy==1.6.0 # via # pytest + # pytest-cov # tox ply==3.11 # via @@ -395,8 +395,10 @@ pycparser==2.22 # via # -r requirements/base.txt # cffi -pygments==2.19.1 - # via -r requirements/base.txt +pygments==2.19.2 + # via + # -r requirements/base.txt + # pytest pyjwt[crypto]==2.10.1 # via # -r requirements/base.txt @@ -405,7 +407,7 @@ pyjwt[crypto]==2.10.1 # edx-drf-extensions # edx-rest-api-client # social-auth-core -pylint==3.3.7 +pylint==3.3.8 # via # edx-lint # pylint-celery @@ -415,13 +417,13 @@ pylint-celery==0.3 # via edx-lint pylint-django==2.6.1 # via edx-lint -pylint-plugin-utils==0.8.2 +pylint-plugin-utils==0.9.0 # via # pylint-celery # pylint-django pymemcache==4.0.0 # via -r requirements/base.txt -pymongo==4.12.1 +pymongo==4.14.0 # via # -r requirements/base.txt # edx-opaque-keys @@ -429,13 +431,13 @@ pynacl==1.5.0 # via # -r requirements/base.txt # edx-django-utils -pyproject-api==1.9.0 +pyproject-api==1.9.1 # via tox -pytest==8.3.5 +pytest==8.4.1 # via # pytest-cov # pytest-django -pytest-cov==6.1.1 +pytest-cov==6.2.1 # via -r requirements/test.in pytest-dictsdiff==0.5.8 # via -r requirements/test.in @@ -466,14 +468,14 @@ pyyaml==6.0.2 # drf-spectacular # drf-yasg # edx-django-release-util -redis==6.0.0 +redis==6.4.0 # via -r requirements/base.txt referencing==0.36.2 # via # -r requirements/base.txt # jsonschema # jsonschema-specifications -requests==2.32.3 +requests==2.32.4 # via # -r requirements/base.txt # analytics-python @@ -487,7 +489,7 @@ requests-oauthlib==2.0.0 # via # -r requirements/base.txt # social-auth-core -rpds-py==0.24.0 +rpds-py==0.27.0 # via # -r requirements/base.txt # jsonschema @@ -516,7 +518,7 @@ social-auth-app-django==5.4.3 # via # -r requirements/base.txt # edx-auth-backends -social-auth-core==4.6.1 +social-auth-core==4.7.0 # via # -r requirements/base.txt # edx-auth-backends @@ -535,13 +537,14 @@ text-unidecode==1.3 # via # -r requirements/base.txt # python-slugify -tomlkit==0.13.2 +tomlkit==0.13.3 # via pylint -tox==4.25.0 +tox==4.28.4 # via -r requirements/test.in -typing-extensions==4.13.2 +typing-extensions==4.14.1 # via # -r requirements/base.txt + # cattrs # django-countries # edx-opaque-keys # referencing @@ -550,15 +553,14 @@ tzdata==2025.2 # -r requirements/base.txt # faker # kombu -uritemplate==4.1.1 +uritemplate==4.2.0 # via # -r requirements/base.txt # coreapi # drf-spectacular # drf-yasg -urllib3==2.2.3 +urllib3==2.5.0 # via - # -c requirements/common_constraints.txt # -r requirements/base.txt # requests vine==5.1.0 @@ -567,7 +569,7 @@ vine==5.1.0 # amqp # celery # kombu -virtualenv==20.30.0 +virtualenv==20.33.1 # via tox wcwidth==0.2.13 # via diff --git a/requirements/validation.txt b/requirements/validation.txt index da1ac3027..4632e43eb 100644 --- a/requirements/validation.txt +++ b/requirements/validation.txt @@ -13,14 +13,14 @@ analytics-python==1.4.post1 # via # -r requirements/quality.txt # -r requirements/test.txt -asgiref==3.8.1 +asgiref==3.9.1 # via # -r requirements/quality.txt # -r requirements/test.txt # django # django-cors-headers # django-countries -astroid==3.3.9 +astroid==3.3.11 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -49,22 +49,22 @@ billiard==4.2.1 # -r requirements/quality.txt # -r requirements/test.txt # celery -cachetools==5.5.2 +cachetools==6.1.0 # via # -r requirements/quality.txt # -r requirements/test.txt # tox -cattrs==24.1.3 +cattrs==25.1.1 # via # -r requirements/quality.txt # -r requirements/test.txt -celery==5.5.2 +celery==5.5.3 # via # -r requirements/quality.txt # -r requirements/test.txt # django-celery-results # edx-celeryutils -certifi==2025.4.26 +certifi==2025.8.3 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -80,12 +80,12 @@ chardet==5.2.0 # -r requirements/quality.txt # -r requirements/test.txt # tox -charset-normalizer==3.4.2 +charset-normalizer==3.4.3 # via # -r requirements/quality.txt # -r requirements/test.txt # requests -click==8.1.8 +click==8.2.1 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -107,7 +107,7 @@ click-log==0.4.0 # -r requirements/quality.txt # -r requirements/test.txt # edx-lint -click-plugins==1.1.1 +click-plugins==1.1.1.2 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -143,12 +143,12 @@ coreschema==0.0.4 # -r requirements/quality.txt # -r requirements/test.txt # coreapi -coverage[toml]==7.8.0 +coverage[toml]==7.10.3 # via # -r requirements/quality.txt # -r requirements/test.txt # pytest-cov -cryptography==44.0.3 +cryptography==45.0.6 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -175,12 +175,12 @@ dill==0.4.0 # -r requirements/quality.txt # -r requirements/test.txt # pylint -distlib==0.3.9 +distlib==0.4.0 # via # -r requirements/quality.txt # -r requirements/test.txt # virtualenv -django==4.2.20 +django==4.2.23 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -259,11 +259,11 @@ django-rest-swagger==2.2.0 # via # -r requirements/quality.txt # -r requirements/test.txt -django-simple-history==3.8.0 +django-simple-history==3.10.1 # via # -r requirements/quality.txt # -r requirements/test.txt -django-waffle==4.2.0 +django-waffle==5.0.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -274,7 +274,7 @@ djangoql==0.18.1 # via # -r requirements/quality.txt # -r requirements/test.txt -djangorestframework==3.16.0 +djangorestframework==3.16.1 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -294,7 +294,7 @@ dnspython==2.7.0 # -r requirements/quality.txt # -r requirements/test.txt # pymongo -docutils==0.21.2 +docutils==0.22 # via # -r requirements/quality.txt # readme-renderer @@ -316,7 +316,7 @@ edx-api-doc-tools==2.1.0 # via # -r requirements/quality.txt # -r requirements/test.txt -edx-auth-backends==4.5.0 +edx-auth-backends==4.6.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -329,7 +329,7 @@ edx-ccx-keys==2.0.2 # -r requirements/quality.txt # -r requirements/test.txt # openedx-events -edx-celeryutils==1.3.0 +edx-celeryutils==1.4.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -337,10 +337,11 @@ edx-django-release-util==1.5.0 # via # -r requirements/quality.txt # -r requirements/test.txt -edx-django-utils==7.4.0 +edx-django-utils==8.0.0 # via # -r requirements/quality.txt # -r requirements/test.txt + # edx-auth-backends # edx-drf-extensions # edx-event-bus-kafka # edx-rest-api-client @@ -351,7 +352,7 @@ edx-drf-extensions==10.6.0 # -r requirements/quality.txt # -r requirements/test.txt # edx-rbac -edx-enterprise-subsidy-client==2.0.3 +edx-enterprise-subsidy-client==2.0.10 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -370,7 +371,7 @@ edx-opaque-keys[django]==3.0.0 # edx-ccx-keys # edx-drf-extensions # openedx-events -edx-rbac==1.10.0 +edx-rbac==2.1.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -379,21 +380,22 @@ edx-rest-api-client==6.2.0 # -r requirements/quality.txt # -r requirements/test.txt # edx-enterprise-subsidy-client -edx-toggles==5.3.0 +edx-toggles==5.4.1 # via # -r requirements/quality.txt # -r requirements/test.txt + # edx-auth-backends # edx-event-bus-kafka factory-boy==3.3.3 # via # -r requirements/quality.txt # -r requirements/test.txt -faker==37.1.0 +faker==37.5.3 # via # -r requirements/quality.txt # -r requirements/test.txt # factory-boy -fastavro==1.10.0 +fastavro==1.12.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -405,7 +407,7 @@ filelock==3.18.0 # -r requirements/test.txt # tox # virtualenv -freezegun==1.5.1 +freezegun==1.5.5 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -447,7 +449,7 @@ jaraco-context==6.0.1 # via # -r requirements/quality.txt # keyring -jaraco-functools==4.1.0 +jaraco-functools==4.2.1 # via # -r requirements/quality.txt # keyring @@ -462,7 +464,7 @@ jinja2==3.1.6 # -r requirements/test.txt # code-annotations # coreschema -jsonfield==3.1.0 +jsonfield==3.2.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -471,7 +473,7 @@ jsonfield2==4.0.0.post0 # via # -r requirements/quality.txt # -r requirements/test.txt -jsonschema==4.23.0 +jsonschema==4.25.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -485,12 +487,12 @@ keyring==25.6.0 # via # -r requirements/quality.txt # twine -kombu==5.5.3 +kombu==5.5.4 # via # -r requirements/quality.txt # -r requirements/test.txt # celery -markdown-it-py==3.0.0 +markdown-it-py==4.0.0 # via # -r requirements/quality.txt # rich @@ -522,16 +524,11 @@ mysqlclient==2.2.7 # via # -r requirements/quality.txt # -r requirements/test.txt -newrelic==10.11.0 - # via - # -r requirements/quality.txt - # -r requirements/test.txt - # edx-django-utils -nh3==0.2.21 +nh3==0.3.0 # via # -r requirements/quality.txt # readme-renderer -oauthlib==3.2.2 +oauthlib==3.3.1 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -542,7 +539,7 @@ openapi-codec==1.3.2 # -r requirements/quality.txt # -r requirements/test.txt # django-rest-swagger -openedx-events==10.1.0 +openedx-events==10.4.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -552,6 +549,7 @@ packaging==25.0 # -r requirements/quality.txt # -r requirements/test.txt # drf-yasg + # kombu # pyproject-api # pytest # tox @@ -561,18 +559,19 @@ pbr==6.1.1 # -r requirements/quality.txt # -r requirements/test.txt # stevedore -platformdirs==4.3.7 +platformdirs==4.3.8 # via # -r requirements/quality.txt # -r requirements/test.txt # pylint # tox # virtualenv -pluggy==1.5.0 +pluggy==1.6.0 # via # -r requirements/quality.txt # -r requirements/test.txt # pytest + # pytest-cov # tox ply==3.11 # via @@ -589,7 +588,7 @@ psutil==7.0.0 # -r requirements/quality.txt # -r requirements/test.txt # edx-django-utils -pycodestyle==2.13.0 +pycodestyle==2.14.0 # via -r requirements/quality.txt pycparser==2.22 # via @@ -598,10 +597,11 @@ pycparser==2.22 # cffi pydocstyle==6.3.0 # via -r requirements/quality.txt -pygments==2.19.1 +pygments==2.19.2 # via # -r requirements/quality.txt # -r requirements/test.txt + # pytest # readme-renderer # rich pyjwt[crypto]==2.10.1 @@ -613,7 +613,7 @@ pyjwt[crypto]==2.10.1 # edx-drf-extensions # edx-rest-api-client # social-auth-core -pylint==3.3.7 +pylint==3.3.8 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -631,7 +631,7 @@ pylint-django==2.6.1 # -r requirements/quality.txt # -r requirements/test.txt # edx-lint -pylint-plugin-utils==0.8.2 +pylint-plugin-utils==0.9.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -641,7 +641,7 @@ pymemcache==4.0.0 # via # -r requirements/quality.txt # -r requirements/test.txt -pymongo==4.12.1 +pymongo==4.14.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -651,18 +651,18 @@ pynacl==1.5.0 # -r requirements/quality.txt # -r requirements/test.txt # edx-django-utils -pyproject-api==1.9.0 +pyproject-api==1.9.1 # via # -r requirements/quality.txt # -r requirements/test.txt # tox -pytest==8.3.5 +pytest==8.4.1 # via # -r requirements/quality.txt # -r requirements/test.txt # pytest-cov # pytest-django -pytest-cov==6.1.1 +pytest-cov==6.2.1 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -708,7 +708,7 @@ readme-renderer==44.0 # via # -r requirements/quality.txt # twine -redis==6.0.0 +redis==6.4.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -718,7 +718,7 @@ referencing==0.36.2 # -r requirements/test.txt # jsonschema # jsonschema-specifications -requests==2.32.3 +requests==2.32.4 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -745,11 +745,11 @@ rfc3986==2.0.0 # via # -r requirements/quality.txt # twine -rich==14.0.0 +rich==14.1.0 # via # -r requirements/quality.txt # twine -rpds-py==0.24.0 +rpds-py==0.27.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -784,7 +784,7 @@ six==1.17.0 # edx-lint # edx-rbac # python-dateutil -snowballstemmer==2.2.0 +snowballstemmer==3.0.1 # via # -r requirements/quality.txt # pydocstyle @@ -793,7 +793,7 @@ social-auth-app-django==5.4.3 # -r requirements/quality.txt # -r requirements/test.txt # edx-auth-backends -social-auth-core==4.6.1 +social-auth-core==4.7.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -816,21 +816,22 @@ text-unidecode==1.3 # -r requirements/quality.txt # -r requirements/test.txt # python-slugify -tomlkit==0.13.2 +tomlkit==0.13.3 # via # -r requirements/quality.txt # -r requirements/test.txt # pylint -tox==4.25.0 +tox==4.28.4 # via # -r requirements/quality.txt # -r requirements/test.txt twine==6.1.0 # via -r requirements/quality.txt -typing-extensions==4.13.2 +typing-extensions==4.14.1 # via # -r requirements/quality.txt # -r requirements/test.txt + # cattrs # django-countries # edx-opaque-keys # referencing @@ -840,14 +841,14 @@ tzdata==2025.2 # -r requirements/test.txt # faker # kombu -uritemplate==4.1.1 +uritemplate==4.2.0 # via # -r requirements/quality.txt # -r requirements/test.txt # coreapi # drf-spectacular # drf-yasg -urllib3==2.2.3 +urllib3==2.5.0 # via # -r requirements/quality.txt # -r requirements/test.txt @@ -860,7 +861,7 @@ vine==5.1.0 # amqp # celery # kombu -virtualenv==20.30.0 +virtualenv==20.33.1 # via # -r requirements/quality.txt # -r requirements/test.txt From ad24a998068c8831bc785a3775efa144cd9cfec8 Mon Sep 17 00:00:00 2001 From: jesperhodge Date: Thu, 14 Aug 2025 13:24:38 -0400 Subject: [PATCH 09/13] fix: lint --- .../apps/content_assignments/signals.py | 2 +- enterprise_access/apps/core/signals.py | 17 ----------------- .../apps/subsidy_access_policy/apps.py | 4 ++++ .../apps/subsidy_access_policy/signals.py | 5 ++--- 4 files changed, 7 insertions(+), 21 deletions(-) delete mode 100644 enterprise_access/apps/core/signals.py diff --git a/enterprise_access/apps/content_assignments/signals.py b/enterprise_access/apps/content_assignments/signals.py index 554e960dc..baefbe4aa 100644 --- a/enterprise_access/apps/content_assignments/signals.py +++ b/enterprise_access/apps/content_assignments/signals.py @@ -8,7 +8,7 @@ from django.db.models.signals import post_save from django.dispatch import receiver from django.utils import timezone -from openedx_events.enterprise.signals import LEDGER_TRANSACTION_REVERSED, ENTERPRISE_GROUP_DELETED +from openedx_events.enterprise.signals import LEDGER_TRANSACTION_REVERSED from enterprise_access.apps.content_assignments.constants import LearnerContentAssignmentStateChoices from enterprise_access.apps.content_assignments.models import LearnerContentAssignment diff --git a/enterprise_access/apps/core/signals.py b/enterprise_access/apps/core/signals.py deleted file mode 100644 index 7f253d2f5..000000000 --- a/enterprise_access/apps/core/signals.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -Signal handlers for content_assignments app. -""" -import logging - -from django.dispatch import receiver -from openedx_events.enterprise.signals import ENTERPRISE_GROUP_DELETED - - -logger = logging.getLogger(__name__) - -@receiver(ENTERPRISE_GROUP_DELETED) -def handle_enterprise_group_deleted(**kwargs): - """ - OEP-49 event handler to update assignment status for reversed transaction. - """ - logger.info('Received ENTERPRISE_GROUP_DELETED signal with data: %s', kwargs) diff --git a/enterprise_access/apps/subsidy_access_policy/apps.py b/enterprise_access/apps/subsidy_access_policy/apps.py index 5306174eb..b8bd89f53 100644 --- a/enterprise_access/apps/subsidy_access_policy/apps.py +++ b/enterprise_access/apps/subsidy_access_policy/apps.py @@ -4,6 +4,10 @@ class SubsidyAccessPolicyConfig(AppConfig): + """ + Initialization app for enterprise_access.apps.subsidy_access_policy. + Necessary so that django signals in this app are registered. + """ default_auto_field = 'django.db.models.BigAutoField' name = 'enterprise_access.apps.subsidy_access_policy' diff --git a/enterprise_access/apps/subsidy_access_policy/signals.py b/enterprise_access/apps/subsidy_access_policy/signals.py index c9d6cd69a..06a7d4df7 100644 --- a/enterprise_access/apps/subsidy_access_policy/signals.py +++ b/enterprise_access/apps/subsidy_access_policy/signals.py @@ -5,11 +5,12 @@ from django.dispatch import receiver from openedx_events.enterprise.signals import ENTERPRISE_GROUP_DELETED -from enterprise_access.apps.subsidy_access_policy.models import PolicyGroupAssociation +from enterprise_access.apps.subsidy_access_policy.models import PolicyGroupAssociation logger = logging.getLogger(__name__) + @receiver(ENTERPRISE_GROUP_DELETED) def handle_enterprise_group_deleted(**kwargs): """ @@ -22,5 +23,3 @@ def handle_enterprise_group_deleted(**kwargs): return deletions = PolicyGroupAssociation.cascade_delete_for_group_uuid(group_uuid) logger.info('PolicyGroupAssociation records deleted: %s', deletions) - - # error handling \ No newline at end of file From 9365213551cc1061281f90baf1d43410d7ba194a Mon Sep 17 00:00:00 2001 From: jesperhodge Date: Thu, 14 Aug 2025 17:11:11 -0400 Subject: [PATCH 10/13] test: signals --- .../apps/subsidy_access_policy/signals.py | 12 +- .../tests/test_signals.py | 133 ++++++++++++++++++ 2 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 enterprise_access/apps/subsidy_access_policy/tests/test_signals.py diff --git a/enterprise_access/apps/subsidy_access_policy/signals.py b/enterprise_access/apps/subsidy_access_policy/signals.py index 06a7d4df7..e7fbed878 100644 --- a/enterprise_access/apps/subsidy_access_policy/signals.py +++ b/enterprise_access/apps/subsidy_access_policy/signals.py @@ -5,6 +5,7 @@ from django.dispatch import receiver from openedx_events.enterprise.signals import ENTERPRISE_GROUP_DELETED +from openedx_events.enterprise.data import EnterpriseGroup from enterprise_access.apps.subsidy_access_policy.models import PolicyGroupAssociation @@ -17,9 +18,12 @@ def handle_enterprise_group_deleted(**kwargs): OEP-49 event handler to update assignment status for reversed transaction. """ logger.info('Received ENTERPRISE_GROUP_DELETED signal with data: %s', kwargs) - group_uuid = kwargs.get('enterprise_group').uuid if 'enterprise_group' in kwargs else None - if not group_uuid: - logger.warning('ENTERPRISE_GROUP_DELETED signal received without a valid group UUID.') - return + group = kwargs.get('enterprise_group') + if not group or not isinstance(group, EnterpriseGroup): + logger.error('ENTERPRISE_GROUP_DELETED signal missing or invalid enterprise_group: %s', kwargs) + raise ValueError('Missing or invalid enterprise_group in signal') + + group_uuid = group.uuid + deletions = PolicyGroupAssociation.cascade_delete_for_group_uuid(group_uuid) logger.info('PolicyGroupAssociation records deleted: %s', deletions) diff --git a/enterprise_access/apps/subsidy_access_policy/tests/test_signals.py b/enterprise_access/apps/subsidy_access_policy/tests/test_signals.py new file mode 100644 index 000000000..a1a360126 --- /dev/null +++ b/enterprise_access/apps/subsidy_access_policy/tests/test_signals.py @@ -0,0 +1,133 @@ +""" +Tests for subsidy_access_policy signals and handlers. +""" +import uuid +from unittest import mock + +from django.test import TestCase + +from openedx_events.enterprise.signals import ENTERPRISE_GROUP_DELETED +from openedx_events.enterprise.data import EnterpriseGroup +from enterprise_access.apps.subsidy_access_policy.models import PolicyGroupAssociation +from enterprise_access.apps.subsidy_access_policy.signals import handle_enterprise_group_deleted +from enterprise_access.apps.subsidy_access_policy.tests.factories import ( + PerLearnerEnrollmentCapLearnerCreditAccessPolicyFactory, + PolicyGroupAssociationFactory +) + + +class TestEnterpriseGroupDeletedSignal(TestCase): + """ + Tests for the ENTERPRISE_GROUP_DELETED signal handler. + """ + + def setUp(self): + """ + Set up test data for the test cases. + """ + super().setUp() + self.group_uuid_1 = uuid.uuid4() + self.group_uuid_2 = uuid.uuid4() + self.group_uuid_3 = uuid.uuid4() + + # Create policies to associate with groups + self.policy_1 = PerLearnerEnrollmentCapLearnerCreditAccessPolicyFactory() + self.policy_2 = PerLearnerEnrollmentCapLearnerCreditAccessPolicyFactory() + self.policy_3 = PerLearnerEnrollmentCapLearnerCreditAccessPolicyFactory() + + # Create policy-group associations + self.association_1 = PolicyGroupAssociationFactory.create( + subsidy_access_policy=self.policy_1, + enterprise_group_uuid=self.group_uuid_1 + ) + self.association_2 = PolicyGroupAssociationFactory.create( + subsidy_access_policy=self.policy_2, + enterprise_group_uuid=self.group_uuid_2 + ) + # Different group that shouldn't be affected + self.association_3 = PolicyGroupAssociationFactory.create( + subsidy_access_policy=self.policy_3, + enterprise_group_uuid=self.group_uuid_3 + ) + + def test_handle_enterprise_group_deleted_direct_call(self): + """ + Test that the signal handler correctly deletes associations when called directly. + """ + # Set up a mock enterprise group + mock_enterprise_group = EnterpriseGroup(uuid=self.group_uuid_1) + + # Verify that associations for group_uuid_1 exist before deletion + self.assertTrue( + PolicyGroupAssociation.objects.filter(enterprise_group_uuid=self.group_uuid_1).exists(), + "Associations for group_uuid_1 should exist before deletion" + ) + + # Call the signal handler directly + handle_enterprise_group_deleted(enterprise_group=mock_enterprise_group) + + # Verify that associations for group_uuid_1 are deleted + self.assertFalse( + PolicyGroupAssociation.objects.filter(enterprise_group_uuid=self.group_uuid_1).exists(), + "Associations for deleted group should be removed" + ) + + # Verify that associations for other groups are not affected + self.assertTrue( + PolicyGroupAssociation.objects.filter(enterprise_group_uuid=self.group_uuid_2).exists(), + "Associations for unrelated groups should not be affected" + ) + + def test_handle_enterprise_group_deleted_via_signal(self): + """ + Test that the signal handler correctly responds to the ENTERPRISE_GROUP_DELETED signal. + """ + # Set up a mock enterprise group + mock_enterprise_group = EnterpriseGroup(uuid=self.group_uuid_2) + + # Verify that associations for group_uuid_1 exist before deletion + self.assertTrue( + PolicyGroupAssociation.objects.filter(enterprise_group_uuid=self.group_uuid_2).exists(), + "Associations for group_uuid_1 should exist before deletion" + ) + + # Send the signal + ENTERPRISE_GROUP_DELETED.send_event(enterprise_group=mock_enterprise_group) + + # Verify that associations for group_uuid_1 are deleted + self.assertFalse( + PolicyGroupAssociation.objects.filter(enterprise_group_uuid=self.group_uuid_2).exists(), + "Associations for deleted group should be removed when signal is sent" + ) + + # Verify that associations for other groups are not affected + self.assertTrue( + PolicyGroupAssociation.objects.filter(enterprise_group_uuid=self.group_uuid_3).exists(), + "Associations for unrelated groups should not be affected when signal is sent" + ) + + def test_handle_enterprise_group_deleted_wrong_kwargs(self): + """ + Test that the signal handler gracefully handles missing UUID. + """ + # Initial count of associations + initial_count = PolicyGroupAssociation.objects.count() + + # Call the signal handler with missing kwargs + with self.assertRaises(ValueError) as e: + handle_enterprise_group_deleted() + # Assert ValueError is raised for missing enterprise_group: + self.assertEqual(str(e.exception), 'Missing or invalid enterprise_group in signal') + + # Call the signal handler with an invalid enterprise_group + with self.assertRaises(ValueError) as e: + handle_enterprise_group_deleted(enterprise_group="invalid_group") + # Assert ValueError is raised for invalid enterprise_group: + self.assertEqual(str(e.exception), 'Missing or invalid enterprise_group in signal') + + # Verify no associations were deleted + self.assertEqual( + PolicyGroupAssociation.objects.count(), + initial_count, + "No associations should be deleted when signal is called with wrong kwargs" + ) From f56731789b09c82f2f4a39b3dd30fde1103448bb Mon Sep 17 00:00:00 2001 From: jesperhodge Date: Thu, 14 Aug 2025 17:13:47 -0400 Subject: [PATCH 11/13] fix: lint --- .../apps/subsidy_access_policy/signals.py | 2 +- .../tests/test_signals.py | 23 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/enterprise_access/apps/subsidy_access_policy/signals.py b/enterprise_access/apps/subsidy_access_policy/signals.py index e7fbed878..61bb86421 100644 --- a/enterprise_access/apps/subsidy_access_policy/signals.py +++ b/enterprise_access/apps/subsidy_access_policy/signals.py @@ -4,8 +4,8 @@ import logging from django.dispatch import receiver -from openedx_events.enterprise.signals import ENTERPRISE_GROUP_DELETED from openedx_events.enterprise.data import EnterpriseGroup +from openedx_events.enterprise.signals import ENTERPRISE_GROUP_DELETED from enterprise_access.apps.subsidy_access_policy.models import PolicyGroupAssociation diff --git a/enterprise_access/apps/subsidy_access_policy/tests/test_signals.py b/enterprise_access/apps/subsidy_access_policy/tests/test_signals.py index a1a360126..efa73f133 100644 --- a/enterprise_access/apps/subsidy_access_policy/tests/test_signals.py +++ b/enterprise_access/apps/subsidy_access_policy/tests/test_signals.py @@ -2,17 +2,16 @@ Tests for subsidy_access_policy signals and handlers. """ import uuid -from unittest import mock from django.test import TestCase - -from openedx_events.enterprise.signals import ENTERPRISE_GROUP_DELETED from openedx_events.enterprise.data import EnterpriseGroup +from openedx_events.enterprise.signals import ENTERPRISE_GROUP_DELETED + from enterprise_access.apps.subsidy_access_policy.models import PolicyGroupAssociation from enterprise_access.apps.subsidy_access_policy.signals import handle_enterprise_group_deleted from enterprise_access.apps.subsidy_access_policy.tests.factories import ( - PerLearnerEnrollmentCapLearnerCreditAccessPolicyFactory, - PolicyGroupAssociationFactory + PerLearnerEnrollmentCapLearnerCreditAccessPolicyFactory, + PolicyGroupAssociationFactory ) @@ -29,12 +28,12 @@ def setUp(self): self.group_uuid_1 = uuid.uuid4() self.group_uuid_2 = uuid.uuid4() self.group_uuid_3 = uuid.uuid4() - + # Create policies to associate with groups self.policy_1 = PerLearnerEnrollmentCapLearnerCreditAccessPolicyFactory() self.policy_2 = PerLearnerEnrollmentCapLearnerCreditAccessPolicyFactory() self.policy_3 = PerLearnerEnrollmentCapLearnerCreditAccessPolicyFactory() - + # Create policy-group associations self.association_1 = PolicyGroupAssociationFactory.create( subsidy_access_policy=self.policy_1, @@ -65,13 +64,13 @@ def test_handle_enterprise_group_deleted_direct_call(self): # Call the signal handler directly handle_enterprise_group_deleted(enterprise_group=mock_enterprise_group) - + # Verify that associations for group_uuid_1 are deleted self.assertFalse( PolicyGroupAssociation.objects.filter(enterprise_group_uuid=self.group_uuid_1).exists(), "Associations for deleted group should be removed" ) - + # Verify that associations for other groups are not affected self.assertTrue( PolicyGroupAssociation.objects.filter(enterprise_group_uuid=self.group_uuid_2).exists(), @@ -93,13 +92,13 @@ def test_handle_enterprise_group_deleted_via_signal(self): # Send the signal ENTERPRISE_GROUP_DELETED.send_event(enterprise_group=mock_enterprise_group) - + # Verify that associations for group_uuid_1 are deleted self.assertFalse( PolicyGroupAssociation.objects.filter(enterprise_group_uuid=self.group_uuid_2).exists(), "Associations for deleted group should be removed when signal is sent" ) - + # Verify that associations for other groups are not affected self.assertTrue( PolicyGroupAssociation.objects.filter(enterprise_group_uuid=self.group_uuid_3).exists(), @@ -118,7 +117,7 @@ def test_handle_enterprise_group_deleted_wrong_kwargs(self): handle_enterprise_group_deleted() # Assert ValueError is raised for missing enterprise_group: self.assertEqual(str(e.exception), 'Missing or invalid enterprise_group in signal') - + # Call the signal handler with an invalid enterprise_group with self.assertRaises(ValueError) as e: handle_enterprise_group_deleted(enterprise_group="invalid_group") From 2425ff14335fc709cbcd92a51d5a55d5f51961ce Mon Sep 17 00:00:00 2001 From: jesperhodge Date: Thu, 14 Aug 2025 17:20:16 -0400 Subject: [PATCH 12/13] test: cascade delete on policy group association --- .../tests/test_models.py | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/enterprise_access/apps/subsidy_access_policy/tests/test_models.py b/enterprise_access/apps/subsidy_access_policy/tests/test_models.py index 5dbc7d93f..56008728c 100644 --- a/enterprise_access/apps/subsidy_access_policy/tests/test_models.py +++ b/enterprise_access/apps/subsidy_access_policy/tests/test_models.py @@ -50,7 +50,8 @@ PerLearnerEnrollmentCreditAccessPolicy, PerLearnerSpendCreditAccessPolicy, SubsidyAccessPolicy, - SubsidyAccessPolicyLockAttemptFailed + SubsidyAccessPolicyLockAttemptFailed, + PolicyGroupAssociation ) from enterprise_access.apps.subsidy_access_policy.tests.factories import ( AssignedLearnerCreditAccessPolicyFactory, @@ -1902,3 +1903,27 @@ def test_save(self): self.assertEqual(policy.enterprise_group_uuid, self.group_uuid) self.assertIsNotNone(policy.subsidy_access_policy) + + def test_cascade_delete_for_group_uuid_should_delete_correct_associations(self): + """ + Test that deleting a group uuid will delete all associations + with that group uuid, and no others. + """ + policy1 = PolicyGroupAssociationFactory( + enterprise_group_uuid=self.group_uuid, + subsidy_access_policy=self.access_policy, + ) + policy2 = PolicyGroupAssociationFactory( + enterprise_group_uuid=uuid4(), + subsidy_access_policy=self.access_policy, + ) + + # Ensure both policies are created + self.assertEqual(PolicyGroupAssociation.objects.count(), 2) + + # Delete the first policy group association + policy1.delete() + + # Ensure only the second policy remains + self.assertEqual(PolicyGroupAssociation.objects.count(), 1) + self.assertEqual(PolicyGroupAssociation.objects.first(), policy2) From 0212e8817cb9dd9ca4bd7c3661a840b02c8f5857 Mon Sep 17 00:00:00 2001 From: jesperhodge Date: Thu, 14 Aug 2025 17:35:05 -0400 Subject: [PATCH 13/13] fix: lint --- .../apps/subsidy_access_policy/tests/test_models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/enterprise_access/apps/subsidy_access_policy/tests/test_models.py b/enterprise_access/apps/subsidy_access_policy/tests/test_models.py index 56008728c..92896205e 100644 --- a/enterprise_access/apps/subsidy_access_policy/tests/test_models.py +++ b/enterprise_access/apps/subsidy_access_policy/tests/test_models.py @@ -49,9 +49,9 @@ REQUEST_CACHE_NAMESPACE, PerLearnerEnrollmentCreditAccessPolicy, PerLearnerSpendCreditAccessPolicy, + PolicyGroupAssociation, SubsidyAccessPolicy, - SubsidyAccessPolicyLockAttemptFailed, - PolicyGroupAssociation + SubsidyAccessPolicyLockAttemptFailed ) from enterprise_access.apps.subsidy_access_policy.tests.factories import ( AssignedLearnerCreditAccessPolicyFactory,