diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b3be035d..0c72b5eb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,11 @@ Unreleased ---------- ========================= +[6.0.0] - 2024-02-13 +--------------------- + * Add streaming csv support + * Add support to avoid call to LMS for filtering enrollments + [5.5.1] - 2024-01-10 --------------------- * Added retry mechanism for failed report deliveries. diff --git a/enterprise_data/__init__.py b/enterprise_data/__init__.py index c5ff52c3..e3a6424c 100644 --- a/enterprise_data/__init__.py +++ b/enterprise_data/__init__.py @@ -2,4 +2,4 @@ Enterprise data api application. This Django app exposes API endpoints used by enterprises. """ -__version__ = "5.5.1" +__version__ = "6.0.0" diff --git a/enterprise_data/api/v1/serializers.py b/enterprise_data/api/v1/serializers.py index e3cb9d8c..3e035455 100644 --- a/enterprise_data/api/v1/serializers.py +++ b/enterprise_data/api/v1/serializers.py @@ -27,7 +27,7 @@ class Meta: model = EnterpriseLearnerEnrollment # Do not change the order of fields below. Ordering is important becuase `progress_v3` # csv generated in `enterprise_reporting` should be same as csv generated on `admin-portal` - # Order and field names below should match with `EnterpriseLearnerEnrollmentViewSet.header` + # Order and field names below should match with `EnrollmentsCSVRenderer.header` fields = ( 'enrollment_id', 'enterprise_enrollment_id', 'is_consent_granted', 'paid_by', 'user_current_enrollment_mode', 'enrollment_date', 'unenrollment_date', diff --git a/enterprise_data/api/v1/views.py b/enterprise_data/api/v1/views.py index 09765f18..05adc2b4 100644 --- a/enterprise_data/api/v1/views.py +++ b/enterprise_data/api/v1/views.py @@ -18,9 +18,12 @@ from rest_framework.status import HTTP_200_OK, HTTP_404_NOT_FOUND from rest_framework.views import APIView +from django.conf import settings +from django.core.paginator import Paginator from django.db.models import Count, Max, OuterRef, Prefetch, Q, Subquery, Value from django.db.models.fields import IntegerField from django.db.models.functions import Coalesce +from django.http import StreamingHttpResponse from django.utils import timezone from enterprise_data.api.v1 import serializers @@ -34,6 +37,7 @@ EnterpriseOffer, ) from enterprise_data.paginators import EnterpriseEnrollmentsPagination +from enterprise_data.renderers import EnrollmentsCSVRenderer from enterprise_data.utils import get_cache_key LOGGER = getLogger(__name__) @@ -81,6 +85,7 @@ class EnterpriseLearnerEnrollmentViewSet(EnterpriseViewSetMixin, viewsets.ReadOn ENROLLMENT_MODE_FILTER = 'user_current_enrollment_mode' COUPON_CODE_FILTER = 'coupon_code' OFFER_FILTER = 'offer_type' + # TODO: Remove after we release the streaming csv changes # This will be used as CSV header for csv generated from `admin-portal`. # Do not change the order of fields below. Ordering is important because csv generated # on `admin-portal` should match `progress_v3` csv generated in `enterprise_reporting` @@ -101,6 +106,7 @@ class EnterpriseLearnerEnrollmentViewSet(EnterpriseViewSetMixin, viewsets.ReadOn 'course_product_line', 'budget_id' ] + # TODO: Remove after we release the streaming csv changes def get_renderer_context(self): renderer_context = super().get_renderer_context() renderer_context['header'] = self.header @@ -124,22 +130,35 @@ def get_queryset(self): if cached_response.is_found: return cached_response.value else: - enterprise = EnterpriseLearner.objects.filter(enterprise_customer_uuid=enterprise_customer_uuid).exists() - - if not enterprise: - LOGGER.warning( - "[Data Overview Failure] Wrong Enterprise UUID. UUID [%s], Endpoint ['%s'], User: [%s]", - enterprise_customer_uuid, - self.request.get_full_path(), - self.request.user.username, - ) - enrollments = EnterpriseLearnerEnrollment.objects.filter(enterprise_customer_uuid=enterprise_customer_uuid) - enrollments = self.apply_filters(enrollments) TieredCache.set_all_tiers(cache_key, enrollments, DEFAULT_LEARNER_CACHE_TIMEOUT) return enrollments + def list(self, request, *args, **kwargs): + """ + Override the list method to handle streaming CSV download. + """ + if self.request.query_params.get('streaming_csv_enabled') == 'true': + if request.accepted_renderer.format == 'csv': + return StreamingHttpResponse( + EnrollmentsCSVRenderer().render(self._stream_serialized_data()), + content_type="text/csv", + headers={"Content-Disposition": 'attachment; filename="learner_progress_report.csv"'}, + ) + + return super().list(request, *args, **kwargs) + + def _stream_serialized_data(self): + """ + Stream the serialized data. + """ + queryset = self.filter_queryset(self.get_queryset()) + serializer = self.get_serializer_class() + paginator = Paginator(queryset, per_page=settings.ENROLLMENTS_PAGE_SIZE) + for page_number in paginator.page_range: + yield from serializer(paginator.page(page_number).object_list, many=True).data + def apply_filters(self, queryset): """ Filters enrollments based on query params. diff --git a/enterprise_data/filters.py b/enterprise_data/filters.py index 0b995b18..1ac096bf 100644 --- a/enterprise_data/filters.py +++ b/enterprise_data/filters.py @@ -73,14 +73,25 @@ class AuditEnrollmentsFilterBackend(filters.BaseFilterBackend, FiltersMixin): `user_current_enrollment_mode` field. """ - def filter_queryset(self, request, queryset, view): + def exclude_audit_enrollments(self, view): """ - Filter out queryset for results where enrollment mode is `audit`. + Determine if audit enrollments should be excluded. """ + # this will be passed from admin-portal to avoid api call to lms + audit_enrollments = view.request.query_params.get('audit_enrollments') + if audit_enrollments: + return audit_enrollments == 'false' + enterprise_uuid = view.kwargs['enterprise_id'] enterprise_customer = self.get_enterprise_customer(enterprise_uuid) + return enterprise_customer.get('enable_audit_data_reporting') is False - if not enterprise_customer.get('enable_audit_data_reporting'): + def filter_queryset(self, request, queryset, view): + """ + Filter out queryset for results where enrollment mode is `audit`. + """ + if self.exclude_audit_enrollments(view): + enterprise_uuid = view.kwargs['enterprise_id'] LOGGER.info(f'[AuditEnrollmentsFilterBackend] excluding audit enrollments for: {enterprise_uuid}') # Filter out enrollments that have audit mode and do not have a coupon code or an offer. filter_query = { diff --git a/enterprise_data/migrations/0039_auto_20240212_1403.py b/enterprise_data/migrations/0039_auto_20240212_1403.py new file mode 100644 index 00000000..f6f976f9 --- /dev/null +++ b/enterprise_data/migrations/0039_auto_20240212_1403.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.23 on 2024-02-12 14:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('enterprise_data', '0038_enterpriseoffer_export_timestamp'), + ] + + operations = [ + migrations.AddIndex( + model_name='enterpriselearnerenrollment', + index=models.Index(fields=['enterprise_customer_uuid', 'enterprise_user_id', 'user_current_enrollment_mode'], name='enterprise__enterpr_6b0be8_idx'), + ), + migrations.AddIndex( + model_name='enterpriselearnerenrollment', + index=models.Index(fields=['enterprise_customer_uuid', 'offer_id', 'budget_id'], name='enterprise__enterpr_66e37f_idx'), + ), + migrations.AddIndex( + model_name='enterpriselearnerenrollment', + index=models.Index(fields=['enterprise_customer_uuid', 'user_current_enrollment_mode', 'coupon_code', 'offer_type'], name='enterprise__enterpr_1e8e98_idx'), + ), + ] diff --git a/enterprise_data/models.py b/enterprise_data/models.py index fe58cbef..342cd184 100644 --- a/enterprise_data/models.py +++ b/enterprise_data/models.py @@ -70,6 +70,13 @@ class Meta: db_table = 'enterprise_learner_enrollment' verbose_name = _("Enterprise Learner Enrollment") verbose_name_plural = _("Enterprise Learner Enrollments") + indexes = [ + models.Index(fields=['enterprise_customer_uuid', 'enterprise_user_id', 'user_current_enrollment_mode']), + models.Index(fields=['enterprise_customer_uuid', 'offer_id', 'budget_id']), + models.Index(fields=[ + 'enterprise_customer_uuid', 'user_current_enrollment_mode', 'coupon_code', 'offer_type' + ]), + ] enterprise_enrollment_id = models.PositiveIntegerField(primary_key=True) enrollment_id = models.PositiveIntegerField(null=True) diff --git a/enterprise_data/renderers.py b/enterprise_data/renderers.py new file mode 100644 index 00000000..5273a39d --- /dev/null +++ b/enterprise_data/renderers.py @@ -0,0 +1,31 @@ +""" +Renderers for enterprise data views. +""" + +from rest_framework_csv.renderers import CSVStreamingRenderer + + +class EnrollmentsCSVRenderer(CSVStreamingRenderer): + """ + Custom streaming csv renderer for EnterpriseLearnerEnrollment data. + """ + + # This will be used as CSV header for csv generated from `admin-portal`. + # Do not change the order of fields below. Ordering is important because csv generated + # on `admin-portal` should match `progress_v3` csv generated in `enterprise_reporting` + # Order and field names below should match with `EnterpriseLearnerEnrollmentSerializer.fields` + header = [ + 'enrollment_id', 'enterprise_enrollment_id', 'is_consent_granted', 'paid_by', + 'user_current_enrollment_mode', 'enrollment_date', 'unenrollment_date', + 'unenrollment_end_within_date', 'is_refunded', 'seat_delivery_method', + 'offer_id', 'offer_name', 'offer_type', 'coupon_code', 'coupon_name', 'contract_id', + 'course_list_price', 'amount_learner_paid', 'course_key', 'courserun_key', + 'course_title', 'course_pacing_type', 'course_start_date', 'course_end_date', + 'course_duration_weeks', 'course_max_effort', 'course_min_effort', + 'course_primary_program', 'primary_program_type', 'course_primary_subject', 'has_passed', + 'last_activity_date', 'progress_status', 'passed_date', 'current_grade', + 'letter_grade', 'enterprise_user_id', 'user_email', 'user_account_creation_date', + 'user_country_code', 'user_username', 'enterprise_name', 'enterprise_customer_uuid', + 'enterprise_sso_uid', 'created', 'course_api_url', 'total_learning_time_hours', 'is_subsidy', + 'course_product_line', 'budget_id' + ] diff --git a/enterprise_data/settings/test.py b/enterprise_data/settings/test.py index fc05f8da..168115c0 100644 --- a/enterprise_data/settings/test.py +++ b/enterprise_data/settings/test.py @@ -104,6 +104,7 @@ def root(*args): SITE_NAME = 'analytics-data-api' ENTERPRISE_REPORTING_DB_ALIAS = 'default' +ENROLLMENTS_PAGE_SIZE = 10000 # Required for use with edx-drf-extensions JWT functionality: # USER_SETTINGS overrides for djangorestframework-jwt APISettings class diff --git a/requirements/base.in b/requirements/base.in index 35b3ce77..3453a660 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -7,6 +7,7 @@ edx-drf-extensions edx-opaque-keys Django django-fernet-fields-v2 +djangorestframework-csv django-filter django-model-utils edx-rbac diff --git a/requirements/base.txt b/requirements/base.txt index 0783c049..776f514d 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -10,22 +10,22 @@ asgiref==3.7.2 # via django asn1crypto==1.5.1 # via snowflake-connector-python -awscli==1.32.24 +awscli==1.32.35 # via -r requirements/reporting.in bcrypt==4.1.2 # via paramiko billiard==3.6.4.0 # via celery -boto3==1.34.24 +boto3==1.34.35 # via -r requirements/reporting.in -botocore==1.34.24 +botocore==1.34.35 # via # awscli # boto3 # s3transfer celery==4.4.7 # via -r requirements/reporting.in -certifi==2023.11.17 +certifi==2024.2.2 # via # py2neo # requests @@ -84,8 +84,11 @@ django-waffle==4.1.0 # edx-drf-extensions djangorestframework==3.14.0 # via + # djangorestframework-csv # drf-jwt # edx-drf-extensions +djangorestframework-csv==3.0.2 + # via -r requirements/base.in docutils==0.16 # via awscli drf-jwt==1.19.2 @@ -95,7 +98,7 @@ edx-django-utils==5.10.1 # -r requirements/base.in # edx-drf-extensions # edx-rest-api-client -edx-drf-extensions==9.1.2 +edx-drf-extensions==10.2.0 # via # -r requirements/base.in # edx-rbac @@ -109,7 +112,7 @@ edx-rest-api-client==5.6.1 # via -r requirements/base.in factory-boy==3.3.0 # via -r requirements/base.in -faker==22.5.0 +faker==22.7.0 # via factory-boy filelock==3.13.1 # via snowflake-connector-python @@ -127,7 +130,7 @@ kombu==4.6.11 # via celery monotonic==1.6 # via py2neo -newrelic==9.5.0 +newrelic==9.6.0 # via edx-django-utils packaging==23.2 # via @@ -176,7 +179,7 @@ python-dateutil==2.8.2 # botocore # faker # vertica-python -pytz==2023.3.post1 +pytz==2024.1 # via # celery # django @@ -212,7 +215,7 @@ six==1.16.0 # vertica-python slumber==0.7.1 # via edx-rest-api-client -snowflake-connector-python==3.6.0 +snowflake-connector-python==3.7.0 # via -r requirements/reporting.in sortedcontainers==2.4.0 # via snowflake-connector-python diff --git a/requirements/ci.txt b/requirements/ci.txt index c9806e87..b8c34511 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -4,7 +4,7 @@ # # make upgrade # -coverage==7.4.0 +coverage==7.4.1 # via -r requirements/ci.in distlib==0.3.8 # via virtualenv @@ -14,9 +14,9 @@ filelock==3.13.1 # virtualenv packaging==23.2 # via tox -platformdirs==4.1.0 +platformdirs==4.2.0 # via virtualenv -pluggy==1.3.0 +pluggy==1.4.0 # via tox py==1.11.0 # via tox diff --git a/requirements/dev.txt b/requirements/dev.txt index 6ac6bb05..b6c3f069 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -10,19 +10,19 @@ asgiref==3.7.2 # via django asn1crypto==1.5.1 # via snowflake-connector-python -astroid==3.0.2 +astroid==3.0.3 # via # pylint # pylint-celery -awscli==1.32.24 +awscli==1.32.35 # via -r requirements/reporting.in bcrypt==4.1.2 # via paramiko billiard==3.6.4.0 # via celery -boto3==1.34.24 +boto3==1.34.35 # via -r requirements/reporting.in -botocore==1.34.24 +botocore==1.34.35 # via # awscli # boto3 @@ -31,7 +31,7 @@ build==1.0.3 # via pip-tools celery==4.4.7 # via -r requirements/reporting.in -certifi==2023.11.17 +certifi==2024.2.2 # via # py2neo # requests @@ -56,7 +56,7 @@ click==8.1.7 # pip-tools click-log==0.4.0 # via edx-lint -code-annotations==1.5.0 +code-annotations==1.6.0 # via edx-lint colorama==0.4.4 # via awscli @@ -68,11 +68,10 @@ cryptography==41.0.7 # pgpy # pyjwt # pyopenssl - # secretstorage # snowflake-connector-python diff-cover==8.0.3 # via -r requirements/dev-enterprise_data.in -dill==0.3.7 +dill==0.3.8 # via pylint distlib==0.3.8 # via virtualenv @@ -109,8 +108,11 @@ django-waffle==4.1.0 # edx-drf-extensions djangorestframework==3.14.0 # via + # djangorestframework-csv # drf-jwt # edx-drf-extensions +djangorestframework-csv==3.0.2 + # via -r requirements/base.in docutils==0.16 # via # awscli @@ -122,7 +124,7 @@ edx-django-utils==5.10.1 # -r requirements/base.in # edx-drf-extensions # edx-rest-api-client -edx-drf-extensions==9.1.2 +edx-drf-extensions==10.2.0 # via # -r requirements/base.in # edx-rbac @@ -142,7 +144,7 @@ edx-rest-api-client==5.6.1 # via -r requirements/base.in factory-boy==3.3.0 # via -r requirements/base.in -faker==22.5.0 +faker==22.7.0 # via factory-boy filelock==3.13.1 # via @@ -168,10 +170,6 @@ isort==5.13.2 # pylint jaraco-classes==3.3.0 # via keyring -jeepney==0.8.0 - # via - # keyring - # secretstorage jinja2==3.1.3 # via # code-annotations @@ -188,7 +186,7 @@ lxml==5.1.0 # via edx-i18n-tools markdown-it-py==3.0.0 # via rich -markupsafe==2.1.4 +markupsafe==2.1.5 # via jinja2 mccabe==0.7.0 # via pylint @@ -198,7 +196,7 @@ monotonic==1.6 # via py2neo more-itertools==10.2.0 # via jaraco-classes -newrelic==9.5.0 +newrelic==9.6.0 # via edx-django-utils nh3==0.2.15 # via readme-renderer @@ -212,7 +210,7 @@ pansi==2020.7.3 # via py2neo paramiko==3.4.0 # via -r requirements/reporting.in -path==16.9.0 +path==16.10.0 # via edx-i18n-tools pbr==6.0.0 # via stevedore @@ -227,7 +225,7 @@ platformdirs==3.11.0 # pylint # snowflake-connector-python # virtualenv -pluggy==1.3.0 +pluggy==1.4.0 # via # diff-cover # tox @@ -292,9 +290,9 @@ python-dateutil==2.8.2 # botocore # faker # vertica-python -python-slugify==8.0.1 +python-slugify==8.0.3 # via code-annotations -pytz==2023.3.post1 +pytz==2024.1 # via # celery # django @@ -331,8 +329,6 @@ s3transfer==0.10.0 # via # awscli # boto3 -secretstorage==3.3.3 - # via keyring semantic-version==2.10.0 # via edx-drf-extensions six==1.16.0 @@ -349,7 +345,7 @@ slumber==0.7.1 # via edx-rest-api-client snowballstemmer==2.2.0 # via pydocstyle -snowflake-connector-python==3.6.0 +snowflake-connector-python==3.7.0 # via -r requirements/reporting.in sortedcontainers==2.4.0 # via snowflake-connector-python diff --git a/requirements/pip.txt b/requirements/pip.txt index a4cf5307..dfa2b778 100644 --- a/requirements/pip.txt +++ b/requirements/pip.txt @@ -8,7 +8,7 @@ wheel==0.42.0 # via -r requirements/pip.in # The following packages are considered to be unsafe in a requirements file: -pip==23.3.2 +pip==24.0 # via -r requirements/pip.in setuptools==69.0.3 # via -r requirements/pip.in diff --git a/requirements/quality.txt b/requirements/quality.txt index fe51ebcc..39138656 100644 --- a/requirements/quality.txt +++ b/requirements/quality.txt @@ -10,19 +10,19 @@ asgiref==3.7.2 # via django asn1crypto==1.5.1 # via snowflake-connector-python -astroid==3.0.2 +astroid==3.0.3 # via # pylint # pylint-celery -awscli==1.32.24 +awscli==1.32.35 # via -r requirements/reporting.in bcrypt==4.1.2 # via paramiko billiard==3.6.4.0 # via celery -boto3==1.34.24 +boto3==1.34.35 # via -r requirements/reporting.in -botocore==1.34.24 +botocore==1.34.35 # via # awscli # boto3 @@ -31,7 +31,7 @@ build==1.0.3 # via pip-tools celery==4.4.7 # via -r requirements/reporting.in -certifi==2023.11.17 +certifi==2024.2.2 # via # py2neo # requests @@ -56,11 +56,11 @@ click==8.1.7 # pip-tools click-log==0.4.0 # via edx-lint -code-annotations==1.5.0 +code-annotations==1.6.0 # via edx-lint colorama==0.4.4 # via awscli -coverage[toml]==7.4.0 +coverage[toml]==7.4.1 # via # coverage # pytest-cov @@ -72,13 +72,12 @@ cryptography==41.0.7 # pgpy # pyjwt # pyopenssl - # secretstorage # snowflake-connector-python ddt==1.7.1 # via -r requirements/test.in diff-cover==8.0.3 # via -r requirements/dev-enterprise_data.in -dill==0.3.7 +dill==0.3.8 # via pylint distlib==0.3.8 # via virtualenv @@ -116,8 +115,11 @@ django-waffle==4.1.0 # edx-drf-extensions djangorestframework==3.14.0 # via + # djangorestframework-csv # drf-jwt # edx-drf-extensions +djangorestframework-csv==3.0.2 + # via -r requirements/base.in docutils==0.16 # via # awscli @@ -129,7 +131,7 @@ edx-django-utils==5.10.1 # -r requirements/base.in # edx-drf-extensions # edx-rest-api-client -edx-drf-extensions==9.1.2 +edx-drf-extensions==10.2.0 # via # -r requirements/base.in # edx-rbac @@ -153,7 +155,7 @@ factory-boy==3.3.0 # via # -r requirements/base.in # -r requirements/test.in -faker==22.5.0 +faker==22.7.0 # via factory-boy filelock==3.13.1 # via @@ -185,10 +187,6 @@ isort==5.13.2 # pylint jaraco-classes==3.3.0 # via keyring -jeepney==0.8.0 - # via - # keyring - # secretstorage jinja2==3.1.3 # via # code-annotations @@ -205,7 +203,7 @@ lxml==5.1.0 # via edx-i18n-tools markdown-it-py==3.0.0 # via rich -markupsafe==2.1.4 +markupsafe==2.1.5 # via jinja2 mccabe==0.7.0 # via pylint @@ -217,7 +215,7 @@ monotonic==1.6 # via py2neo more-itertools==10.2.0 # via jaraco-classes -newrelic==9.5.0 +newrelic==9.6.0 # via edx-django-utils nh3==0.2.15 # via readme-renderer @@ -232,7 +230,7 @@ pansi==2020.7.3 # via py2neo paramiko==3.4.0 # via -r requirements/reporting.in -path==16.9.0 +path==16.10.0 # via edx-i18n-tools pbr==6.0.0 # via stevedore @@ -247,7 +245,7 @@ platformdirs==3.11.0 # pylint # snowflake-connector-python # virtualenv -pluggy==1.3.0 +pluggy==1.4.0 # via # diff-cover # pytest @@ -308,13 +306,13 @@ pyopenssl==23.3.0 # via snowflake-connector-python pyproject-hooks==1.0.0 # via build -pytest==7.4.4 +pytest==8.0.0 # via # pytest-cov # pytest-django pytest-cov==4.1.0 # via -r requirements/test.in -pytest-django==4.7.0 +pytest-django==4.8.0 # via -r requirements/test.in python-dateutil==2.8.2 # via @@ -322,9 +320,9 @@ python-dateutil==2.8.2 # faker # freezegun # vertica-python -python-slugify==8.0.1 +python-slugify==8.0.3 # via code-annotations -pytz==2023.3.post1 +pytz==2024.1 # via # celery # django @@ -365,8 +363,6 @@ s3transfer==0.10.0 # via # awscli # boto3 -secretstorage==3.3.3 - # via keyring semantic-version==2.10.0 # via edx-drf-extensions six==1.16.0 @@ -383,7 +379,7 @@ slumber==0.7.1 # via edx-rest-api-client snowballstemmer==2.2.0 # via pydocstyle -snowflake-connector-python==3.6.0 +snowflake-connector-python==3.7.0 # via -r requirements/reporting.in sortedcontainers==2.4.0 # via snowflake-connector-python diff --git a/requirements/test-master.txt b/requirements/test-master.txt index 5deba8c3..b7748d95 100644 --- a/requirements/test-master.txt +++ b/requirements/test-master.txt @@ -10,22 +10,22 @@ asgiref==3.7.2 # via django asn1crypto==1.5.1 # via snowflake-connector-python -awscli==1.32.24 +awscli==1.32.35 # via -r requirements/reporting.in bcrypt==4.1.2 # via paramiko billiard==3.6.4.0 # via celery -boto3==1.34.24 +boto3==1.34.35 # via -r requirements/reporting.in -botocore==1.34.24 +botocore==1.34.35 # via # awscli # boto3 # s3transfer celery==4.4.7 # via -r requirements/reporting.in -certifi==2023.11.17 +certifi==2024.2.2 # via # py2neo # requests @@ -43,7 +43,7 @@ click==8.1.7 # via edx-django-utils colorama==0.4.4 # via awscli -coverage[toml]==7.4.0 +coverage[toml]==7.4.1 # via # coverage # pytest-cov @@ -92,8 +92,11 @@ django-waffle==4.1.0 djangorestframework==3.14.0 # via # -r requirements/test-master.in + # djangorestframework-csv # drf-jwt # edx-drf-extensions +djangorestframework-csv==3.0.2 + # via -r requirements/base.in docutils==0.16 # via awscli drf-jwt==1.19.2 @@ -103,7 +106,7 @@ edx-django-utils==5.10.1 # -r requirements/base.in # edx-drf-extensions # edx-rest-api-client -edx-drf-extensions==9.1.2 +edx-drf-extensions==10.2.0 # via # -r requirements/base.in # -r requirements/test-master.in @@ -122,7 +125,7 @@ factory-boy==3.3.0 # via # -r requirements/base.in # -r requirements/test.in -faker==22.5.0 +faker==22.7.0 # via factory-boy filelock==3.13.1 # via snowflake-connector-python @@ -148,7 +151,7 @@ mock==5.1.0 # via -r requirements/test.in monotonic==1.6 # via py2neo -newrelic==9.5.0 +newrelic==9.6.0 # via edx-django-utils packaging==23.2 # via @@ -165,7 +168,7 @@ pgpy==0.6.0 # via -r requirements/reporting.in platformdirs==3.11.0 # via snowflake-connector-python -pluggy==1.3.0 +pluggy==1.4.0 # via pytest psutil==5.9.8 # via edx-django-utils @@ -195,13 +198,13 @@ pynacl==1.5.0 # paramiko pyopenssl==23.3.0 # via snowflake-connector-python -pytest==7.4.4 +pytest==8.0.0 # via # pytest-cov # pytest-django pytest-cov==4.1.0 # via -r requirements/test.in -pytest-django==4.7.0 +pytest-django==4.8.0 # via -r requirements/test.in python-dateutil==2.8.2 # via @@ -209,7 +212,7 @@ python-dateutil==2.8.2 # faker # freezegun # vertica-python -pytz==2023.3.post1 +pytz==2024.1 # via # celery # django @@ -250,7 +253,7 @@ six==1.16.0 # vertica-python slumber==0.7.1 # via edx-rest-api-client -snowflake-connector-python==3.6.0 +snowflake-connector-python==3.7.0 # via -r requirements/reporting.in sortedcontainers==2.4.0 # via snowflake-connector-python diff --git a/requirements/test-reporting.txt b/requirements/test-reporting.txt index 13a84431..19ce4bd5 100644 --- a/requirements/test-reporting.txt +++ b/requirements/test-reporting.txt @@ -12,22 +12,22 @@ atomicwrites==1.4.1 # via pytest attrs==23.2.0 # via pytest -awscli==1.32.24 +awscli==1.32.35 # via -r requirements/reporting.in bcrypt==4.1.2 # via paramiko billiard==3.6.4.0 # via celery -boto3==1.34.24 +boto3==1.34.35 # via -r requirements/reporting.in -botocore==1.34.24 +botocore==1.34.35 # via # awscli # boto3 # s3transfer celery==4.4.7 # via -r requirements/reporting.in -certifi==2023.11.17 +certifi==2024.2.2 # via # py2neo # requests @@ -43,7 +43,7 @@ charset-normalizer==3.3.2 # snowflake-connector-python colorama==0.4.4 # via awscli -coverage==7.4.0 +coverage==7.4.1 # via pytest-cov cryptography==41.0.7 # via @@ -98,7 +98,7 @@ platformdirs==3.11.0 # via # snowflake-connector-python # virtualenv -pluggy==1.3.0 +pluggy==1.4.0 # via # pytest # tox @@ -134,7 +134,7 @@ python-dateutil==2.8.2 # via # botocore # vertica-python -pytz==2023.3.post1 +pytz==2024.1 # via # celery # interchange @@ -165,7 +165,7 @@ six==1.16.0 # python-dateutil # tox # vertica-python -snowflake-connector-python==3.6.0 +snowflake-connector-python==3.7.0 # via -r requirements/reporting.in sortedcontainers==2.4.0 # via snowflake-connector-python diff --git a/requirements/test.txt b/requirements/test.txt index d5273bb0..6800c90d 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -10,22 +10,22 @@ asgiref==3.7.2 # via django asn1crypto==1.5.1 # via snowflake-connector-python -awscli==1.32.24 +awscli==1.32.35 # via -r requirements/reporting.in bcrypt==4.1.2 # via paramiko billiard==3.6.4.0 # via celery -boto3==1.34.24 +boto3==1.34.35 # via -r requirements/reporting.in -botocore==1.34.24 +botocore==1.34.35 # via # awscli # boto3 # s3transfer celery==4.4.7 # via -r requirements/reporting.in -certifi==2023.11.17 +certifi==2024.2.2 # via # py2neo # requests @@ -43,7 +43,7 @@ click==8.1.7 # via edx-django-utils colorama==0.4.4 # via awscli -coverage[toml]==7.4.0 +coverage[toml]==7.4.1 # via # coverage # pytest-cov @@ -91,8 +91,11 @@ django-waffle==4.1.0 # edx-drf-extensions djangorestframework==3.14.0 # via + # djangorestframework-csv # drf-jwt # edx-drf-extensions +djangorestframework-csv==3.0.2 + # via -r requirements/base.in docutils==0.16 # via awscli drf-jwt==1.19.2 @@ -102,7 +105,7 @@ edx-django-utils==5.10.1 # -r requirements/base.in # edx-drf-extensions # edx-rest-api-client -edx-drf-extensions==9.1.2 +edx-drf-extensions==10.2.0 # via # -r requirements/base.in # edx-rbac @@ -120,7 +123,7 @@ factory-boy==3.3.0 # via # -r requirements/base.in # -r requirements/test.in -faker==22.5.0 +faker==22.7.0 # via factory-boy filelock==3.13.1 # via snowflake-connector-python @@ -146,7 +149,7 @@ mock==5.1.0 # via -r requirements/test.in monotonic==1.6 # via py2neo -newrelic==9.5.0 +newrelic==9.6.0 # via edx-django-utils packaging==23.2 # via @@ -163,7 +166,7 @@ pgpy==0.6.0 # via -r requirements/reporting.in platformdirs==3.11.0 # via snowflake-connector-python -pluggy==1.3.0 +pluggy==1.4.0 # via pytest psutil==5.9.8 # via edx-django-utils @@ -193,13 +196,13 @@ pynacl==1.5.0 # paramiko pyopenssl==23.3.0 # via snowflake-connector-python -pytest==7.4.4 +pytest==8.0.0 # via # pytest-cov # pytest-django pytest-cov==4.1.0 # via -r requirements/test.in -pytest-django==4.7.0 +pytest-django==4.8.0 # via -r requirements/test.in python-dateutil==2.8.2 # via @@ -207,7 +210,7 @@ python-dateutil==2.8.2 # faker # freezegun # vertica-python -pytz==2023.3.post1 +pytz==2024.1 # via # celery # django @@ -248,7 +251,7 @@ six==1.16.0 # vertica-python slumber==0.7.1 # via edx-rest-api-client -snowflake-connector-python==3.6.0 +snowflake-connector-python==3.7.0 # via -r requirements/reporting.in sortedcontainers==2.4.0 # via snowflake-connector-python