diff --git a/.github/workflows/check-reserved-keywords.yml b/.github/workflows/check-reserved-keywords.yml index 7c535ade..8dc23dc3 100644 --- a/.github/workflows/check-reserved-keywords.yml +++ b/.github/workflows/check-reserved-keywords.yml @@ -6,7 +6,7 @@ on: jobs: check-reserved-keywords: name: Check Reserved Keywords - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Checkout code @@ -15,7 +15,7 @@ jobs: - name: setup python uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: 3.11 - name: Install pip run: pip install -r requirements/pip.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4c78cb0..15ac556e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,9 +13,9 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04] - python-version: ['3.8'] - toxenv: [django32, django42, quality] + os: [ubuntu-latest] + python-version: ['3.11'] + toxenv: [django42, quality] steps: - uses: actions/checkout@v2 @@ -36,16 +36,17 @@ jobs: run: tox - name: Run Coverage - if: matrix.python-version == '3.8' && matrix.toxenv=='django42' - uses: codecov/codecov-action@v2 + if: matrix.python-version == '3.11' && matrix.toxenv=='django42' + uses: codecov/codecov-action@v4 with: flags: unittests fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} provider-verification: name: Pact Provider Verification - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest needs: run_tests steps: @@ -55,14 +56,14 @@ jobs: - name: setup python uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: 3.11 - name: Install pip run: pip install -r requirements/pip.txt - name: Install Dependencies run: | - pip install "Django<4.0" + pip install "Django>=4.2,<4.3" pip install -r requirements/ci.txt pip install -r requirements/test.txt diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml index 50d307a9..ed0ff513 100644 --- a/.github/workflows/pypi-publish.yml +++ b/.github/workflows/pypi-publish.yml @@ -7,7 +7,7 @@ on: jobs: push: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Checkout @@ -15,7 +15,7 @@ jobs: - name: setup python uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: 3.11 - name: Install pip run: pip install -r requirements/pip.txt @@ -27,7 +27,7 @@ jobs: run: python setup.py sdist bdist_wheel - name: Publish to PyPi - uses: pypa/gh-action-pypi-publish@master + uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.PYPI_UPLOAD_TOKEN }} diff --git a/.github/workflows/upgrade-python-requirements.yml b/.github/workflows/upgrade-python-requirements.yml index 7ed882cf..2045cb15 100644 --- a/.github/workflows/upgrade-python-requirements.yml +++ b/.github/workflows/upgrade-python-requirements.yml @@ -13,8 +13,8 @@ jobs: call-upgrade-python-requirements-workflow: with: branch: ${{ github.event.inputs.branch }} - team_reviewers: "Incident Management" - email_address: incident-management@edx.org + team_reviewers: '2u-phoenix' + email_address: 'phoenix@2u.com' send_success_notification: false secrets: requirements_bot_github_token: ${{ secrets.REQUIREMENTS_BOT_GITHUB_TOKEN }} diff --git a/.github/workflows/verify_changed_contract.yml b/.github/workflows/verify_changed_contract.yml index d9f05a34..9673967c 100644 --- a/.github/workflows/verify_changed_contract.yml +++ b/.github/workflows/verify_changed_contract.yml @@ -15,7 +15,7 @@ env: jobs: changed-contract-verification: name: Pact Provider Verification for a changed contract - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - name: Checkout code @@ -24,7 +24,7 @@ jobs: - name: setup python uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: 3.11 - name: Install pip run: pip install -r requirements/pip.txt diff --git a/edxval/__init__.py b/edxval/__init__.py index 7a5b9868..9f88fe94 100644 --- a/edxval/__init__.py +++ b/edxval/__init__.py @@ -2,4 +2,4 @@ init """ -__version__ = '2.4.2' +__version__ = '2.6.1' diff --git a/edxval/api.py b/edxval/api.py index f631693c..b7455066 100644 --- a/edxval/api.py +++ b/edxval/api.py @@ -733,6 +733,64 @@ def get_videos_for_course(course_id, sort_field=None, sort_dir=SortDirection.asc ) +def get_transcript_details_for_course(course_id): + """ + Get all the transcripts for a course and return details. + + Args: + course_id (String) + + Returns: + (dict): Returns all the edx_video_id's and related transcript details for a course + { + 'edx_video_id': { + 'lang_code': { + 'provider': 'What the provider is', + 'file_format': 'file format', + 'url': 'location of the file', + 'name': 'name of the file', + 'size': size of the file + } + } + """ + course_transcripts_data = {} + + course_videos = CourseVideo.objects.filter(course_id=course_id).select_related('video') + for course_video in course_videos: + + edx_video_id = course_video.video.edx_video_id + transcript_data = {} + + video_transcripts = VideoTranscript.objects.filter(video=course_video.video) + for video_transcript in video_transcripts: + transcript_data[video_transcript.language_code] = { + 'provider': video_transcript.provider, + 'file_format': video_transcript.file_format, + 'url': video_transcript.transcript.url, + 'name': video_transcript.transcript.name, + 'size': video_transcript.transcript.size, + } + + course_transcripts_data[edx_video_id] = transcript_data + + return course_transcripts_data + + +def get_video_ids_for_course(course_id): + """ + Gets video_ids for a course. + + Args: + course_id (String) + + Returns: + (list): Returns all the edx_video_id's for a course + """ + course_videos = CourseVideo.objects.filter(course_id=course_id).select_related('video') + video_ids = [cv.video.edx_video_id for cv in course_videos] + return video_ids + + def remove_video_for_course(course_id, edx_video_id): """ Soft deletes video for particular course. @@ -1018,7 +1076,7 @@ def create_transcripts_xml(video_id, video_el, resource_fs, static_dir): continue SubElement( - transcripts_el, + transcripts_el, # pylint: disable=possibly-used-before-assignment 'transcript', { 'language_code': language_code, @@ -1030,7 +1088,9 @@ def create_transcripts_xml(video_id, video_el, resource_fs, static_dir): return dict(xml=video_el, transcripts=transcript_files_map) -def import_from_xml(xml, edx_video_id, resource_fs, static_dir, external_transcripts=None, course_id=None): +def import_from_xml( + xml, edx_video_id, resource_fs, static_dir, external_transcripts=None, course_id=None +): # pylint: disable=too-many-positional-arguments """ Imports data from a video_asset element about the given video_id. If the edx_video_id already exists, then no changes are made. If an unknown @@ -1147,7 +1207,9 @@ def import_from_xml(xml, edx_video_id, resource_fs, static_dir, external_transcr return edx_video_id -def import_transcript_from_fs(edx_video_id, language_code, file_name, provider, resource_fs, static_dir): +def import_transcript_from_fs( + edx_video_id, language_code, file_name, provider, resource_fs, static_dir +): # pylint: disable=too-many-positional-arguments """ Imports transcript file from file system and creates transcript record in DS. diff --git a/edxval/models.py b/edxval/models.py index 03cb4ad0..56b0ac9b 100644 --- a/edxval/models.py +++ b/edxval/models.py @@ -485,7 +485,9 @@ def get_or_none(cls, video_id, language_code): return transcript @classmethod - def create(cls, video, language_code, file_format, content, provider): + def create( + cls, video, language_code, file_format, content, provider + ): # pylint: disable=too-many-positional-arguments """ Create a Video Transcript. diff --git a/edxval/pacts/middleware.py b/edxval/pacts/middleware.py index 12ab544e..f04d7bbf 100644 --- a/edxval/pacts/middleware.py +++ b/edxval/pacts/middleware.py @@ -19,10 +19,9 @@ class AuthenticationMiddleware(MiddlewareMixin): """ def __init__(self, get_response): - super().__init__() + super().__init__(get_response) self.auth_user = User.objects.get_or_create(username='edx', is_staff=True)[0] self.auth_user.user_permissions.set(Permission.objects.filter(content_type__app_label='edxval')) - self.get_response = get_response def process_view(self, request, view_func, view_args, view_kwargs): # pylint: disable=unused-argument """ diff --git a/edxval/tests/constants.py b/edxval/tests/constants.py index 500c2dbd..53168e5c 100644 --- a/edxval/tests/constants.py +++ b/edxval/tests/constants.py @@ -386,6 +386,13 @@ status="test", ) +VIDEO_DICT_SIMPSONS = dict( + client_video_id="TheSimpsons", + duration=100.00, + edx_video_id="simpson-id", + status="test", +) + TRANSCRIPT_DATA = { "overwatch": """ 1 @@ -452,3 +459,30 @@ preferred_languages=['ar', 'en'], video_source_language='en', ) + +VIDEO_TRANSCRIPT_SIMPSON_ES = dict( + video_id='simpson-id', + language_code='es', + transcript='edxval/tests/data/The_Flash.srt', + provider=TranscriptProviderType.CIELO24, + file_format=TranscriptFormat.SRT, + file_data=TRANSCRIPT_DATA['flash'] +) + +VIDEO_TRANSCRIPT_SIMPSON_KO = dict( + video_id='simpson-id', + language_code='ko', + transcript='edxval/tests/data/The_Flash.srt', + provider=TranscriptProviderType.CIELO24, + file_format=TranscriptFormat.SRT, + file_data=TRANSCRIPT_DATA['flash'] +) + +VIDEO_TRANSCRIPT_SIMPSON_RU = dict( + video_id='simpson-id', + language_code='ru', + transcript='edxval/tests/data/The_Flash.srt', + provider=TranscriptProviderType.CIELO24, + file_format=TranscriptFormat.SRT, + file_data=TRANSCRIPT_DATA['flash'] +) diff --git a/edxval/tests/test_api.py b/edxval/tests/test_api.py index 6907f862..75e2eb2e 100644 --- a/edxval/tests/test_api.py +++ b/edxval/tests/test_api.py @@ -749,6 +749,18 @@ def api_func(_expected_ids, sort_field, sort_direction): return videos self.check_sort_params_of_api(api_func) + def test_get_video_ids_for_course(self): + + course_transcript = api.get_video_ids_for_course(self.course_id) + + self.assertEqual(len(course_transcript), 1) + + def test_get_video_ids_for_course_no_course_videos(self): + + course_transcript = api.get_video_ids_for_course('this-is-not-a-course-id') + + self.assertEqual(len(course_transcript), 0) + @ddt class GetYouTubeProfileVideosTest(TestCase): @@ -2684,6 +2696,12 @@ def setUp(self): self.v2_transcript1 = video_and_transcripts['transcripts']['de'] self.v2_transcript2 = video_and_transcripts['transcripts']['zh'] + # Add the videos to courses + self.course_id1 = 'test-course-1' + self.course_id2 = 'test-course-2' + CourseVideo.objects.create(video=self.video1, course_id=self.course_id1) + CourseVideo.objects.create(video=self.video2, course_id=self.course_id2) + self.temp_dir = mkdtemp() self.addCleanup(shutil.rmtree, self.temp_dir) @@ -2822,7 +2840,9 @@ def test_get_video_transcript_url(self): }, ) @unpack - def test_create_or_update_video_transcript(self, file_data, file_name, file_format, language_code, provider): + def test_create_or_update_video_transcript( + self, file_data, file_name, file_format, language_code, provider + ): # pylint: disable=too-many-positional-arguments """ Verify that `create_or_update_video_transcript` api function updates existing transcript as expected. """ @@ -2879,7 +2899,9 @@ def test_create_or_update_video_transcript(self, file_data, file_name, file_form }, ) @unpack - def test_create_or_update_video_exceptions(self, video_id, file_format, provider, exception, exception_message): + def test_create_or_update_video_exceptions( + self, video_id, file_format, provider, exception, exception_message + ): # pylint: disable=too-many-positional-arguments """ Verify that `create_or_update_video_transcript` api function raise exceptions on invalid values. """ @@ -2997,7 +3019,9 @@ def test_create_video_transcript(self): } ) @unpack - def test_create_video_transcript_exceptions(self, video_id, language_code, file_format, provider, exception_msg): + def test_create_video_transcript_exceptions( + self, video_id, language_code, file_format, provider, exception_msg + ): # pylint: disable=too-many-positional-arguments """ Verify that `create_video_transcript` api function raise exceptions on invalid values. """ @@ -3133,6 +3157,31 @@ def test_no_create_transcript_file(self, video_id, language_code): # Verify no file is created. self.assertEqual(file_system.listdir(constants.EXPORT_IMPORT_STATIC_DIR), []) + def test_get_transcript_details_for_course(self): + """ + Verify that `get_transcript_details_for_course` api function works as expected. + """ + + course_transcript = api.get_transcript_details_for_course(self.course_id1) + + self.assertEqual(course_transcript['super-soaker']['en']['provider'], TranscriptProviderType.THREE_PLAY_MEDIA) + self.assertEqual(course_transcript['super-soaker']['en']['file_format'], utils.TranscriptFormat.SRT) + self.assertIn('url', course_transcript['super-soaker']['en']) + self.assertIn('name', course_transcript['super-soaker']['en']) + self.assertIn('size', course_transcript['super-soaker']['en']) + + self.assertEqual(course_transcript['super-soaker']['fr']['provider'], TranscriptProviderType.CIELO24) + self.assertEqual(course_transcript['super-soaker']['en']['file_format'], utils.TranscriptFormat.SRT) + self.assertIn('url', course_transcript['super-soaker']['fr']) + self.assertIn('name', course_transcript['super-soaker']['fr']) + self.assertIn('size', course_transcript['super-soaker']['fr']) + + def test_get_transcript_details_for_course_no_course_videos(self): + + course_transcript = api.get_transcript_details_for_course('this-is-not-a-course-id') + + self.assertEqual(len(course_transcript), 0) + @ddt class TranscriptPreferencesTest(TestCase): diff --git a/edxval/tests/test_views.py b/edxval/tests/test_views.py index 236a9848..6d1b8dd2 100644 --- a/edxval/tests/test_views.py +++ b/edxval/tests/test_views.py @@ -4,10 +4,13 @@ import json +from unittest.mock import patch from ddt import data, ddt, unpack from django.urls import reverse +from edx_rest_framework_extensions.permissions import IsStaff from rest_framework import status +from rest_framework.permissions import IsAuthenticated from edxval.models import CourseVideo, EncodedVideo, Profile, TranscriptProviderType, Video, VideoTranscript from edxval.serializers import TranscriptSerializer @@ -1101,3 +1104,120 @@ def test_update_hls_encodes_for_video(self): self.assertEqual(actual_encoded_video.url, expected_data['encode_data']['url']) self.assertEqual(actual_encoded_video.file_size, expected_data['encode_data']['file_size']) self.assertEqual(actual_encoded_video.bitrate, expected_data['encode_data']['bitrate']) + + +class CourseTranscriptsDetailViewTest(APIAuthTestCase): + """ + CourseTranscriptsDetailView Tests. + """ + base_url = 'course-transcripts' + + def test_successful_response(self): + """ + Test succesful response from view + """ + with patch( + 'edxval.views.get_transcript_details_for_course' + ) as mock_transcript_details: + # Simulate a return value when the function is called. + mock_transcript_details.return_value = {} + course_id = 'course-v1:edx+1+2023_05' + url = reverse(self.base_url, args=[course_id]) + response = self.client.get(url) + + # Verify the function was called once with course_id + mock_transcript_details.assert_called_once_with(course_id) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + +class CourseVideoIDsViewTest(APIAuthTestCase): + """ + CourseVideoIDsViewTest Tests. + """ + base_url = 'course-transcripts' + + def test_successful_response(self): + """ + Test succesful response from view + """ + with patch( + 'edxval.views.get_video_ids_for_course' + ) as mock_video_ids: + # Simulate a return value when the function is called. + mock_video_ids.return_value = [] + course_id = 'course-v1:edx+1+2023_05' + url = reverse('course-video-ids', args=[course_id]) + response = self.client.get(url) + + # Verify the function was called once with course_id + mock_video_ids.assert_called_once_with(course_id) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + + +@ddt +class VideoTranscriptDeleteTest(APIAuthTestCase): + """ + Tests for transcript bulk deletion handler. + """ + def setUp(self): + """ + Tests setup. + """ + self.url = reverse('video-transcripts') + self.patcher = patch.object(IsAuthenticated, "has_permission", return_value=True) + self.patcher = patch.object(IsStaff, "has_permission", return_value=True) + self.patcher.start() + + self.video_1 = Video.objects.create(**constants.VIDEO_DICT_SIMPSONS) + self.transcript_data_es = constants.VIDEO_TRANSCRIPT_SIMPSON_ES + self.transcript_data_ko = constants.VIDEO_TRANSCRIPT_SIMPSON_KO + self.transcript_data_ru = constants.VIDEO_TRANSCRIPT_SIMPSON_RU + super().setUp() + + def tearDown(self): + self.patcher.stop() + + def test_transcript_fail_authorized(self): + with patch.object(IsAuthenticated, "has_permission", return_value=False): + response = self.client.delete(self.url) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + def test_transcript_delete_fail_no_staff(self): + with patch.object(IsStaff, "has_permission", return_value=False): + response = self.client.delete(self.url) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + def test_transcript_delete_success(self): + VideoTranscript.objects.create( + video=self.video_1, + language_code=self.transcript_data_es['language_code'], + file_format=self.transcript_data_es['file_format'], + provider=self.transcript_data_es['provider'], + ) + VideoTranscript.objects.create( + video=self.video_1, + language_code=self.transcript_data_ko['language_code'], + file_format=self.transcript_data_ko['file_format'], + provider=self.transcript_data_ko['provider'], + ) + VideoTranscript.objects.create( + video=self.video_1, + language_code=self.transcript_data_ru['language_code'], + file_format=self.transcript_data_ru['file_format'], + provider=self.transcript_data_ru['provider'], + ) + + response1 = self.client.delete(f'{self.url}?video_id=simpson-id&language_code=es') + self.assertEqual(response1.status_code, status.HTTP_204_NO_CONTENT) + + response2 = self.client.delete(f'{self.url}?video_id=simpson-id&language_code=ko') + self.assertEqual(response2.status_code, status.HTTP_204_NO_CONTENT) + + response3 = self.client.delete(f'{self.url}?video_id=simpson-id&language_code=ru') + self.assertEqual(response3.status_code, status.HTTP_204_NO_CONTENT) + + def test_transcript_delete_fail_bad_request(self): + response = self.client.delete(self.url) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) diff --git a/edxval/urls.py b/edxval/urls.py index cd48c945..d985746d 100644 --- a/edxval/urls.py +++ b/edxval/urls.py @@ -19,12 +19,21 @@ path('videos/missing-hls/', views.HLSMissingVideoView.as_view(), name='hls-missing-video' ), + path('videos/course-transcripts//', views.CourseTranscriptsDetailView.as_view(), + name='course-transcripts' + ), path('videos/video-transcripts/create/', views.VideoTranscriptView.as_view(), name='create-video-transcript' ), + path('videos/video-transcripts/', views.VideoTranscriptView.as_view(), + name='video-transcripts' + ), path('videos/video-images/update/', views.VideoImagesView.as_view(), name='update-video-images' ), + path('videos/courses//video-ids', views.CourseVideoIDsView.as_view(), + name='course-video-ids' + ), ] if getattr(settings, 'PROVIDER_STATES_SETUP_VIEW_URL', None): diff --git a/edxval/views.py b/edxval/views.py index 1dd6eda3..0a340451 100644 --- a/edxval/views.py +++ b/edxval/views.py @@ -8,13 +8,19 @@ from django.core.exceptions import ValidationError from django.shortcuts import get_object_or_404 from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication +from edx_rest_framework_extensions.permissions import IsStaff from rest_framework import generics, status from rest_framework.authentication import SessionAuthentication -from rest_framework.permissions import DjangoModelPermissions +from rest_framework.permissions import DjangoModelPermissions, IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView -from edxval.api import create_or_update_video_transcript +from edxval.api import ( + create_or_update_video_transcript, + delete_video_transcript, + get_transcript_details_for_course, + get_video_ids_for_course, +) from edxval.models import ( LIST_MAX_ITEMS, CourseVideo, @@ -119,7 +125,11 @@ class VideoTranscriptView(APIView): """ authentication_classes = (JwtAuthentication, SessionAuthentication) - # noinspection PyMethodMayBeStatic + def get_permissions(self): + if self.request.method == 'DELETE': + return [IsAuthenticated(), IsStaff()] + return [] + def post(self, request): """ Creates a video transcript instance with the given information. @@ -174,6 +184,70 @@ def post(self, request): return response + def delete(self, request): + """ + Delete a video transcript instance with the given information. + + Arguments: + request: A WSGI request. + """ + params = ('video_id', 'language_code') + missing = [param for param in params if param not in request.query_params] + if missing: + LOGGER.warning( + '[VAL] Required transcript params are missing. %s', ' and '.join(missing) + ) + return Response( + status=status.HTTP_400_BAD_REQUEST, + data=dict(message='{missing} must be specified.'.format(missing=' and '.join(missing))) + ) + + video_id = request.query_params.get('video_id') + language_code = request.query_params.get('language_code') + + try: + delete_video_transcript(video_id=video_id, language_code=language_code) + except Exception as e: # pylint: disable=broad-exception-caught + return Response( + status=status.HTTP_500_INTERNAL_SERVER_ERROR, + data={'message': str(e)} + ) + + return Response( + status=status.HTTP_204_NO_CONTENT, + ) + + +class CourseTranscriptsDetailView(APIView): + """ + A view to get the details for all the course transcripts related to a course_id. + """ + authentication_classes = (JwtAuthentication, SessionAuthentication) + + def get(self, _request, course_id): + """ + Returns all transcript data for a course when given a course_id. + """ + if not course_id: + return Response(status=status.HTTP_400_BAD_REQUEST, data={'message': 'course_id param required'}) + + course_data = get_transcript_details_for_course(course_id) + return Response(status=status.HTTP_200_OK, data=course_data) + + +class CourseVideoIDsView(APIView): + """ + A view to get video ids related to a course_id. + """ + authentication_classes = (JwtAuthentication, SessionAuthentication) + + def get(self, _, course_id): + """ + Returns all video_ids for a course when given a course_id. + """ + video_ids = get_video_ids_for_course(course_id) + return Response(status=status.HTTP_200_OK, data=video_ids) + class VideoStatusView(APIView): """ @@ -252,7 +326,7 @@ def post(self, request): try: validate_generated_images(generated_images, LIST_MAX_ITEMS) - except Exception as e: # pylint: disable=broad-except + except Exception as e: # pylint: disable=broad-exception-caught return Response( status=status.HTTP_400_BAD_REQUEST, data={'message': str(e)} diff --git a/pylintrc b/pylintrc index 4a4cf450..3d02a0de 100644 --- a/pylintrc +++ b/pylintrc @@ -64,7 +64,7 @@ # SERIOUSLY. # # ------------------------------ -# Generated by edx-lint version: 5.3.0 +# Generated by edx-lint version: 5.3.7 # ------------------------------ [MASTER] ignore = migrations @@ -259,6 +259,7 @@ enable = useless-suppression, disable = bad-indentation, + broad-exception-raised, consider-using-f-string, duplicate-code, file-ignored, @@ -380,6 +381,6 @@ ext-import-graph = int-import-graph = [EXCEPTIONS] -overgeneral-exceptions = Exception +overgeneral-exceptions = builtins.Exception -# e4144201a3f25df503e5cbb5cc51147c12a2d137 +# 9e382112fd455855f6d0f08cef2bdb5077da2d63 diff --git a/requirements/ci.in b/requirements/ci.in index 45e13317..b161bd0f 100644 --- a/requirements/ci.in +++ b/requirements/ci.in @@ -4,4 +4,3 @@ coveralls # Code coverage reporting tox # Virtualenv management for tests -tox-battery # Makes tox aware of requirements file changes diff --git a/requirements/ci.txt b/requirements/ci.txt index 85d97125..e603bef7 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -1,49 +1,50 @@ # -# This file is autogenerated by pip-compile with Python 3.8 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # make upgrade # -certifi==2023.5.7 +cachetools==5.5.0 + # via tox +certifi==2024.8.30 # via requests -charset-normalizer==3.1.0 +chardet==5.2.0 + # via tox +charset-normalizer==3.4.0 # via requests -coverage==6.5.0 +colorama==0.4.6 + # via tox +coverage[toml]==7.6.8 # via coveralls -coveralls==3.3.1 +coveralls==4.0.1 # via -r requirements/ci.in -distlib==0.3.6 +distlib==0.3.9 # via virtualenv docopt==0.6.2 # via coveralls -filelock==3.12.0 +filelock==3.16.1 # via # tox # virtualenv -idna==3.4 +idna==3.10 # via requests -packaging==23.1 - # via tox -platformdirs==3.5.1 - # via virtualenv -pluggy==1.0.0 +packaging==24.2 + # via + # pyproject-api + # tox +platformdirs==4.3.6 + # via + # tox + # virtualenv +pluggy==1.5.0 # via tox -py==1.11.0 +pyproject-api==1.8.0 # via tox -requests==2.31.0 +requests==2.32.3 # via coveralls -six==1.16.0 - # via tox -tomli==2.0.1 - # via tox -tox==3.28.0 - # via - # -c requirements/common_constraints.txt - # -r requirements/ci.in - # tox-battery -tox-battery==0.6.1 +tox==4.23.2 # via -r requirements/ci.in -urllib3==2.0.2 +urllib3==2.2.3 # via requests -virtualenv==20.23.0 +virtualenv==20.28.0 # via tox diff --git a/requirements/common_constraints.txt b/requirements/common_constraints.txt index 7e39123f..a58adb9a 100644 --- a/requirements/common_constraints.txt +++ b/requirements/common_constraints.txt @@ -11,22 +11,17 @@ # Note: Changes to this file will automatically be used by other repos, referencing # this file from Github directly. It does not require packaging in edx-lint. - # using LTS django version -Django<4.0 +Django<5.0 # elasticsearch>=7.14.0 includes breaking changes in it which caused issues in discovery upgrade process. # elastic search changelog: https://www.elastic.co/guide/en/enterprise-search/master/release-notes-7.14.0.html +# 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 django-simple-history==3.0.0 -# tox>4.0.0 isn't yet compatible with many tox plugins, causing CI failures in almost all repos. -# Details can be found in this discussion: https://github.com/tox-dev/tox/discussions/1810 -tox<4.0.0 - -# edx-sphinx-theme is not compatible with latest Sphinx==6.0.0 version -# Pinning Sphinx version unless the compatibility issue gets resolved -# For details, see issue https://github.com/openedx/edx-sphinx-theme/issues/197 -sphinx<6.0.0 +# 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 diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 116e8bf2..ee0577a1 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -10,3 +10,8 @@ # Common constraints for edx repos -c common_constraints.txt + +# 5.4.0 is breaking for Python 3.8 and 3.11 CI checks with error +# importlib.resources' has no attribute 'files' +# To be unpinned once edx-val moves to Python 3.12 +edx-lint==5.3.7 \ No newline at end of file diff --git a/requirements/dev.txt b/requirements/dev.txt index bb5123c6..926b544c 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -1,39 +1,40 @@ # -# This file is autogenerated by pip-compile with Python 3.8 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # make upgrade # -anyio==3.7.0 - # via - # httpcore - # starlette +annotated-types==0.7.0 + # via pydantic +anyio==4.7.0 + # via starlette appdirs==1.4.4 # via fs -asgiref==3.7.2 +asgiref==3.8.1 # via django -astroid==2.15.5 +astroid==3.3.5 # via # pylint # pylint-celery -bleach==6.0.0 - # via readme-renderer -certifi==2023.5.7 - # via - # httpcore - # httpx - # requests -cffi==1.15.1 +backports-tarfile==1.2.0 + # via jaraco-context +cachetools==5.5.0 + # via tox +certifi==2024.8.30 + # via requests +cffi==1.17.1 # via # cryptography + # pact-python # pynacl -chardet==5.1.0 +chardet==5.2.0 # via # diff-cover # pysrt -charset-normalizer==3.1.0 + # tox +charset-normalizer==3.4.0 # via requests -click==8.1.3 +click==8.1.7 # via # click-log # code-annotations @@ -43,37 +44,39 @@ click==8.1.3 # uvicorn click-log==0.4.0 # via edx-lint -code-annotations==1.3.0 +code-annotations==2.0.0 # via # edx-lint # edx-toggles -coverage[toml]==6.5.0 +colorama==0.4.6 + # via tox +coverage[toml]==7.6.8 # via # -r requirements/test.in # coveralls # pytest-cov -coveralls==3.3.1 +coveralls==4.0.1 # via -r requirements/ci.in -cryptography==41.0.1 +cryptography==44.0.0 # via - # djfernet # pyjwt # secretstorage -ddt==1.6.0 +ddt==1.7.2 # via -r requirements/test.in -diff-cover==7.5.0 +diff-cover==9.2.0 # via -r requirements/dev.in -dill==0.3.6 +dill==0.3.9 # via pylint -distlib==0.3.6 +distlib==0.3.9 # via virtualenv -django==3.2.19 +django==4.2.17 # via # -c requirements/common_constraints.txt # -r requirements/base.in # django-crum # django-model-utils # django-storages + # django-waffle # djangorestframework # drf-jwt # edx-django-release-util @@ -84,152 +87,154 @@ django-crum==0.7.9 # via # edx-django-utils # edx-toggles -django-model-utils==4.3.1 +django-model-utils==5.0.0 # via -r requirements/base.in -django-storages==1.13.2 +django-storages==1.14.4 # via -r requirements/base.in -django-waffle==3.0.0 +django-waffle==4.2.0 # via # edx-django-utils # edx-drf-extensions # edx-toggles -djangorestframework==3.14.0 +djangorestframework==3.15.2 # via # drf-jwt # edx-drf-extensions - # via -r requirements/base.in +dnspython==2.7.0 + # via pymongo docopt==0.6.2 # via coveralls -docutils==0.20.1 +docutils==0.21.2 # via readme-renderer drf-jwt==1.19.2 # via edx-drf-extensions -edx-django-release-util==1.2.0 +edx-django-release-util==1.4.0 # via -r requirements/base.in -edx-django-utils==5.5.0 +edx-django-utils==7.1.0 # via # edx-drf-extensions # edx-toggles -edx-drf-extensions==8.8.0 +edx-drf-extensions==10.5.0 # via -r requirements/base.in -edx-lint==5.3.4 - # via -r requirements/quality.in -edx-opaque-keys==2.3.0 +edx-lint==5.3.7 + # via + # -c requirements/constraints.txt + # -r requirements/quality.in +edx-opaque-keys==2.11.0 # via edx-drf-extensions -edx-toggles==5.0.0 +edx-toggles==5.2.0 # via -r requirements/base.in -exceptiongroup==1.1.1 - # via - # anyio - # pytest -fastapi==0.95.2 +fastapi==0.115.6 # via pact-python -filelock==3.12.0 +filelock==3.16.1 # via # tox # virtualenv fs==2.4.16 # via -r requirements/test.in h11==0.14.0 - # via - # httpcore - # uvicorn -httpcore==0.16.3 - # via httpx -httpx==0.23.1 - # via pact-python -idna==3.4 + # via uvicorn +idna==3.10 # via # anyio # requests - # rfc3986 -importlib-metadata==6.6.0 - # via - # keyring - # twine -importlib-resources==5.12.0 + # yarl +importlib-metadata==8.5.0 # via keyring iniconfig==2.0.0 # via pytest -isort==5.12.0 +isort==5.13.2 # via # -r requirements/quality.in # pylint -jaraco-classes==3.2.3 +jaraco-classes==3.4.0 + # via keyring +jaraco-context==6.0.1 + # via keyring +jaraco-functools==4.1.0 # via keyring jeepney==0.8.0 # via # keyring # secretstorage -jinja2==3.1.2 +jinja2==3.1.4 # via # code-annotations # diff-cover -keyring==23.13.1 +keyring==25.5.0 # via twine -lazy-object-proxy==1.9.0 - # via astroid -lxml==4.9.2 +lxml==5.3.0 # via -r requirements/base.in -markdown-it-py==2.2.0 +markdown-it-py==3.0.0 # via rich -markupsafe==2.1.2 +markupsafe==3.0.2 # via jinja2 mccabe==0.7.0 # via pylint mdurl==0.1.2 # via markdown-it-py -mock==5.0.2 +mock==5.1.0 # via -r requirements/test.in -more-itertools==9.1.0 - # via jaraco-classes -newrelic==8.8.0 +more-itertools==10.5.0 + # via + # jaraco-classes + # jaraco-functools +multidict==6.1.0 + # via yarl +newrelic==10.3.1 # via edx-django-utils -packaging==23.1 +nh3==0.2.19 + # via readme-renderer +packaging==24.2 # via + # pyproject-api # pytest # tox -pact-python==1.7.0 + # twine +pact-python==2.2.2 # via -r requirements/test.in -pbr==5.11.1 +pbr==6.1.0 # via stevedore -pillow==9.5.0 +pillow==11.0.0 # via -r requirements/base.in -pkginfo==1.9.6 +pkginfo==1.12.0 # via twine -platformdirs==3.5.1 +platformdirs==4.3.6 # via # pylint + # tox # virtualenv -pluggy==1.0.0 +pluggy==1.5.0 # via # diff-cover # pytest # tox -psutil==5.9.5 +propcache==0.2.1 + # via yarl +psutil==6.1.0 # via # edx-django-utils # pact-python -py==1.11.0 - # via tox -pycodestyle==2.10.0 +pycodestyle==2.12.1 # via -r requirements/quality.in -pycparser==2.21 +pycparser==2.22 # via cffi -pydantic==1.10.8 +pydantic==2.10.3 # via fastapi +pydantic-core==2.27.1 + # via pydantic pydocstyle==6.3.0 # via -r requirements/quality.in -pygments==2.15.1 +pygments==2.18.0 # via # diff-cover # readme-renderer # rich -pyjwt[crypto]==2.7.0 +pyjwt[crypto]==2.10.1 # via # drf-jwt # edx-drf-extensions -pylint==2.17.4 +pylint==3.3.2 # via # edx-lint # pylint-celery @@ -237,42 +242,38 @@ pylint==2.17.4 # pylint-plugin-utils pylint-celery==0.3 # via edx-lint -pylint-django==2.5.3 +pylint-django==2.6.1 # via edx-lint pylint-plugin-utils==0.8.2 # via # pylint-celery # pylint-django -pymongo==3.13.0 +pymongo==4.10.1 # via edx-opaque-keys pynacl==1.5.0 # via edx-django-utils +pyproject-api==1.8.0 + # via tox pysrt==1.1.2 # via -r requirements/base.in -pytest==7.3.1 +pytest==8.3.4 # via # pytest-cov # pytest-django -pytest-cov==4.1.0 +pytest-cov==6.0.0 # via -r requirements/test.in -pytest-django==4.5.2 +pytest-django==4.9.0 # via -r requirements/test.in -python-dateutil==2.8.2 - # via edx-drf-extensions -python-slugify==8.0.1 +python-slugify==8.0.4 # via code-annotations -pytz==2023.3 - # via - # django - # djangorestframework -pyyaml==6.0 +pyyaml==6.0.2 # via # code-annotations # edx-django-release-util # responses -readme-renderer==37.3 +readme-renderer==44.0 # via twine -requests==2.31.0 +requests==2.32.3 # via # coveralls # edx-drf-extensions @@ -282,91 +283,63 @@ requests==2.31.0 # twine requests-toolbelt==1.0.0 # via twine -responses==0.23.1 +responses==0.25.3 # via -r requirements/test.in -rfc3986[idna2008]==1.5.0 - # via - # httpx - # twine -rich==13.4.1 +rfc3986==2.0.0 + # via twine +rich==13.9.4 # via twine secretstorage==3.3.3 # via keyring semantic-version==2.10.0 # via edx-drf-extensions -six==1.16.0 +six==1.17.0 # via - # bleach # edx-django-release-util - # edx-drf-extensions # edx-lint # fs # pact-python - # python-dateutil - # tox -sniffio==1.3.0 - # via - # anyio - # httpcore - # httpx +sniffio==1.3.1 + # via anyio snowballstemmer==2.2.0 # via pydocstyle -sqlparse==0.4.4 +sqlparse==0.5.2 # via django -starlette==0.27.0 +starlette==0.41.3 # via fastapi -stevedore==5.1.0 +stevedore==5.4.0 # via # code-annotations # edx-django-utils # edx-opaque-keys text-unidecode==1.3 # via python-slugify -tomli==2.0.1 - # via - # coverage - # pylint - # pytest - # tox -tomlkit==0.11.8 +tomlkit==0.13.2 # via pylint -tox==3.28.0 - # via - # -c requirements/common_constraints.txt - # -r requirements/ci.in - # tox-battery -tox-battery==0.6.1 +tox==4.23.2 # via -r requirements/ci.in -twine==4.0.2 +twine==6.0.1 # via -r requirements/quality.in -types-pyyaml==6.0.12.10 - # via responses -typing-extensions==4.6.3 +typing-extensions==4.12.2 # via - # asgiref - # astroid + # anyio + # edx-opaque-keys + # fastapi # pydantic - # pylint - # rich - # starlette -urllib3==2.0.2 + # pydantic-core +urllib3==2.2.3 # via - # pact-python # requests # responses # twine -uvicorn==0.22.0 +uvicorn==0.32.1 # via pact-python -virtualenv==20.23.0 +virtualenv==20.28.0 # via tox -webencodings==0.5.1 - # via bleach -wrapt==1.15.0 - # via astroid -zipp==3.15.0 - # via - # importlib-metadata - # importlib-resources +yarl==1.18.3 + # via pact-python +zipp==3.21.0 + # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/requirements/pip-tools.txt b/requirements/pip-tools.txt index fd0cc1c7..83082782 100644 --- a/requirements/pip-tools.txt +++ b/requirements/pip-tools.txt @@ -1,22 +1,22 @@ # -# This file is autogenerated by pip-compile with Python 3.8 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # make upgrade # -build==0.10.0 +build==1.2.2.post1 # via pip-tools -click==8.1.3 +click==8.1.7 # via pip-tools -packaging==23.1 +packaging==24.2 # via build -pip-tools==6.13.0 +pip-tools==7.4.1 # via -r requirements/pip-tools.in -pyproject-hooks==1.0.0 - # via build -tomli==2.0.1 - # via build -wheel==0.40.0 +pyproject-hooks==1.2.0 + # via + # build + # pip-tools +wheel==0.45.1 # via pip-tools # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements/pip.txt b/requirements/pip.txt index 5a5ce227..5c1ced51 100644 --- a/requirements/pip.txt +++ b/requirements/pip.txt @@ -1,14 +1,16 @@ # -# This file is autogenerated by pip-compile with Python 3.8 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # make upgrade # -wheel==0.40.0 +wheel==0.45.1 # via -r requirements/pip.in # The following packages are considered to be unsafe in a requirements file: -pip==23.1.2 - # via -r requirements/pip.in -setuptools==67.8.0 +pip==24.2 + # via + # -c /home/runner/work/edx-val/edx-val/requirements/common_constraints.txt + # -r requirements/pip.in +setuptools==75.6.0 # via -r requirements/pip.in diff --git a/requirements/quality.txt b/requirements/quality.txt index a7435748..5a060e2a 100644 --- a/requirements/quality.txt +++ b/requirements/quality.txt @@ -1,37 +1,35 @@ # -# This file is autogenerated by pip-compile with Python 3.8 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # make upgrade # -anyio==3.7.0 - # via - # httpcore - # starlette +annotated-types==0.7.0 + # via pydantic +anyio==4.7.0 + # via starlette appdirs==1.4.4 # via fs -asgiref==3.7.2 +asgiref==3.8.1 # via django -astroid==2.15.5 +astroid==3.3.5 # via # pylint # pylint-celery -bleach==6.0.0 - # via readme-renderer -certifi==2023.5.7 - # via - # httpcore - # httpx - # requests -cffi==1.15.1 +backports-tarfile==1.2.0 + # via jaraco-context +certifi==2024.8.30 + # via requests +cffi==1.17.1 # via # cryptography + # pact-python # pynacl -chardet==5.1.0 +chardet==5.2.0 # via pysrt -charset-normalizer==3.1.0 +charset-normalizer==3.4.0 # via requests -click==8.1.3 +click==8.1.7 # via # click-log # code-annotations @@ -41,30 +39,30 @@ click==8.1.3 # uvicorn click-log==0.4.0 # via edx-lint -code-annotations==1.3.0 +code-annotations==2.0.0 # via # edx-lint # edx-toggles -coverage[toml]==7.2.7 +coverage[toml]==7.6.8 # via # -r requirements/test.in # pytest-cov -cryptography==41.0.1 +cryptography==44.0.0 # via - # djfernet # pyjwt # secretstorage -ddt==1.6.0 +ddt==1.7.2 # via -r requirements/test.in -dill==0.3.6 +dill==0.3.9 # via pylint -django==3.2.19 +django==4.2.17 # via # -c requirements/common_constraints.txt # -r requirements/base.in # django-crum # django-model-utils # django-storages + # django-waffle # djangorestframework # drf-jwt # edx-django-release-util @@ -75,134 +73,137 @@ django-crum==0.7.9 # via # edx-django-utils # edx-toggles -django-model-utils==4.3.1 +django-model-utils==5.0.0 # via -r requirements/base.in -django-storages==1.13.2 +django-storages==1.14.4 # via -r requirements/base.in -django-waffle==3.0.0 +django-waffle==4.2.0 # via # edx-django-utils # edx-drf-extensions # edx-toggles -djangorestframework==3.14.0 +djangorestframework==3.15.2 # via # drf-jwt # edx-drf-extensions - # via -r requirements/base.in -docutils==0.20.1 +dnspython==2.7.0 + # via pymongo +docutils==0.21.2 # via readme-renderer drf-jwt==1.19.2 # via edx-drf-extensions -edx-django-release-util==1.2.0 +edx-django-release-util==1.4.0 # via -r requirements/base.in -edx-django-utils==5.5.0 +edx-django-utils==7.1.0 # via # edx-drf-extensions # edx-toggles -edx-drf-extensions==8.8.0 +edx-drf-extensions==10.5.0 # via -r requirements/base.in -edx-lint==5.3.4 - # via -r requirements/quality.in -edx-opaque-keys==2.3.0 +edx-lint==5.3.7 + # via + # -c requirements/constraints.txt + # -r requirements/quality.in +edx-opaque-keys==2.11.0 # via edx-drf-extensions -edx-toggles==5.0.0 +edx-toggles==5.2.0 # via -r requirements/base.in -exceptiongroup==1.1.1 - # via - # anyio - # pytest -fastapi==0.95.2 +fastapi==0.115.6 # via pact-python fs==2.4.16 # via -r requirements/test.in h11==0.14.0 - # via - # httpcore - # uvicorn -httpcore==0.16.3 - # via httpx -httpx==0.23.1 - # via pact-python -idna==3.4 + # via uvicorn +idna==3.10 # via # anyio # requests - # rfc3986 -importlib-metadata==6.6.0 - # via - # keyring - # twine -importlib-resources==5.12.0 + # yarl +importlib-metadata==8.5.0 # via keyring iniconfig==2.0.0 # via pytest -isort==5.12.0 +isort==5.13.2 # via # -r requirements/quality.in # pylint -jaraco-classes==3.2.3 +jaraco-classes==3.4.0 + # via keyring +jaraco-context==6.0.1 + # via keyring +jaraco-functools==4.1.0 # via keyring jeepney==0.8.0 # via # keyring # secretstorage -jinja2==3.1.2 +jinja2==3.1.4 # via code-annotations -keyring==23.13.1 +keyring==25.5.0 # via twine -lazy-object-proxy==1.9.0 - # via astroid -lxml==4.9.2 +lxml==5.3.0 # via -r requirements/base.in -markdown-it-py==2.2.0 +markdown-it-py==3.0.0 # via rich -markupsafe==2.1.2 +markupsafe==3.0.2 # via jinja2 mccabe==0.7.0 # via pylint mdurl==0.1.2 # via markdown-it-py -mock==5.0.2 +mock==5.1.0 # via -r requirements/test.in -more-itertools==9.1.0 - # via jaraco-classes -newrelic==8.8.0 +more-itertools==10.5.0 + # via + # jaraco-classes + # jaraco-functools +multidict==6.1.0 + # via yarl +newrelic==10.3.1 # via edx-django-utils -packaging==23.1 - # via pytest -pact-python==1.7.0 +nh3==0.2.19 + # via readme-renderer +packaging==24.2 + # via + # pytest + # twine +pact-python==2.2.2 # via -r requirements/test.in -pbr==5.11.1 +pbr==6.1.0 # via stevedore -pillow==9.5.0 +pillow==11.0.0 # via -r requirements/base.in -pkginfo==1.9.6 +pkginfo==1.12.0 # via twine -platformdirs==3.5.1 +platformdirs==4.3.6 # via pylint -pluggy==1.0.0 +pluggy==1.5.0 # via pytest -psutil==5.9.5 +propcache==0.2.1 + # via yarl +psutil==6.1.0 # via # edx-django-utils # pact-python -pycodestyle==2.10.0 +pycodestyle==2.12.1 # via -r requirements/quality.in -pycparser==2.21 +pycparser==2.22 # via cffi -pydantic==1.10.8 +pydantic==2.10.3 # via fastapi +pydantic-core==2.27.1 + # via pydantic pydocstyle==6.3.0 # via -r requirements/quality.in -pygments==2.15.1 +pygments==2.18.0 # via # readme-renderer # rich -pyjwt[crypto]==2.7.0 +pyjwt[crypto]==2.10.1 # via # drf-jwt # edx-drf-extensions -pylint==2.17.4 +pylint==3.3.2 # via # edx-lint # pylint-celery @@ -210,42 +211,36 @@ pylint==2.17.4 # pylint-plugin-utils pylint-celery==0.3 # via edx-lint -pylint-django==2.5.3 +pylint-django==2.6.1 # via edx-lint pylint-plugin-utils==0.8.2 # via # pylint-celery # pylint-django -pymongo==3.13.0 +pymongo==4.10.1 # via edx-opaque-keys pynacl==1.5.0 # via edx-django-utils pysrt==1.1.2 # via -r requirements/base.in -pytest==7.3.1 +pytest==8.3.4 # via # pytest-cov # pytest-django -pytest-cov==4.1.0 +pytest-cov==6.0.0 # via -r requirements/test.in -pytest-django==4.5.2 +pytest-django==4.9.0 # via -r requirements/test.in -python-dateutil==2.8.2 - # via edx-drf-extensions -python-slugify==8.0.1 +python-slugify==8.0.4 # via code-annotations -pytz==2023.3 - # via - # django - # djangorestframework -pyyaml==6.0 +pyyaml==6.0.2 # via # code-annotations # edx-django-release-util # responses -readme-renderer==37.3 +readme-renderer==44.0 # via twine -requests==2.31.0 +requests==2.32.3 # via # edx-drf-extensions # pact-python @@ -254,80 +249,59 @@ requests==2.31.0 # twine requests-toolbelt==1.0.0 # via twine -responses==0.23.1 +responses==0.25.3 # via -r requirements/test.in -rfc3986[idna2008]==1.5.0 - # via - # httpx - # twine -rich==13.4.1 +rfc3986==2.0.0 + # via twine +rich==13.9.4 # via twine secretstorage==3.3.3 # via keyring semantic-version==2.10.0 # via edx-drf-extensions -six==1.16.0 +six==1.17.0 # via - # bleach # edx-django-release-util - # edx-drf-extensions # edx-lint # fs # pact-python - # python-dateutil -sniffio==1.3.0 - # via - # anyio - # httpcore - # httpx +sniffio==1.3.1 + # via anyio snowballstemmer==2.2.0 # via pydocstyle -sqlparse==0.4.4 +sqlparse==0.5.2 # via django -starlette==0.27.0 +starlette==0.41.3 # via fastapi -stevedore==5.1.0 +stevedore==5.4.0 # via # code-annotations # edx-django-utils # edx-opaque-keys text-unidecode==1.3 # via python-slugify -tomli==2.0.1 - # via - # coverage - # pylint - # pytest -tomlkit==0.11.8 +tomlkit==0.13.2 # via pylint -twine==4.0.2 +twine==6.0.1 # via -r requirements/quality.in -types-pyyaml==6.0.12.10 - # via responses -typing-extensions==4.6.3 +typing-extensions==4.12.2 # via - # asgiref - # astroid + # anyio + # edx-opaque-keys + # fastapi # pydantic - # pylint - # rich - # starlette -urllib3==2.0.2 + # pydantic-core +urllib3==2.2.3 # via - # pact-python # requests # responses # twine -uvicorn==0.22.0 +uvicorn==0.32.1 # via pact-python -webencodings==0.5.1 - # via bleach -wrapt==1.15.0 - # via astroid -zipp==3.15.0 - # via - # importlib-metadata - # importlib-resources +yarl==1.18.3 + # via pact-python +zipp==3.21.0 + # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/requirements/test.txt b/requirements/test.txt index e5c6d795..f967bee3 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -1,47 +1,43 @@ # -# This file is autogenerated by pip-compile with Python 3.8 +# This file is autogenerated by pip-compile with Python 3.11 # by the following command: # # make upgrade # -anyio==3.7.0 - # via - # httpcore - # starlette +annotated-types==0.7.0 + # via pydantic +anyio==4.7.0 + # via starlette appdirs==1.4.4 # via fs -asgiref==3.7.2 +asgiref==3.8.1 # via django -certifi==2023.5.7 - # via - # httpcore - # httpx - # requests -cffi==1.15.1 +certifi==2024.8.30 + # via requests +cffi==1.17.1 # via # cryptography + # pact-python # pynacl -chardet==5.1.0 +chardet==5.2.0 # via pysrt -charset-normalizer==3.1.0 +charset-normalizer==3.4.0 # via requests -click==8.1.3 +click==8.1.7 # via # code-annotations # edx-django-utils # pact-python # uvicorn -code-annotations==1.3.0 +code-annotations==2.0.0 # via edx-toggles -coverage[toml]==7.2.7 +coverage[toml]==7.6.8 # via # -r requirements/test.in # pytest-cov -cryptography==41.0.1 - # via - # djfernet - # pyjwt -ddt==1.6.0 +cryptography==44.0.0 + # via pyjwt +ddt==1.7.2 # via -r requirements/test.in # via # -c requirements/common_constraints.txt @@ -49,6 +45,7 @@ ddt==1.6.0 # django-crum # django-model-utils # django-storages + # django-waffle # djangorestframework # drf-jwt # edx-django-release-util @@ -59,167 +56,148 @@ django-crum==0.7.9 # via # edx-django-utils # edx-toggles -django-model-utils==4.3.1 +django-model-utils==5.0.0 # via -r requirements/base.in -django-storages==1.13.2 +django-storages==1.14.4 # via -r requirements/base.in -django-waffle==3.0.0 +django-waffle==4.2.0 # via # edx-django-utils # edx-drf-extensions # edx-toggles -djangorestframework==3.14.0 +djangorestframework==3.15.2 # via # drf-jwt # edx-drf-extensions - # via -r requirements/base.in +dnspython==2.7.0 + # via pymongo drf-jwt==1.19.2 # via edx-drf-extensions -edx-django-release-util==1.2.0 +edx-django-release-util==1.4.0 # via -r requirements/base.in -edx-django-utils==5.5.0 +edx-django-utils==7.1.0 # via # edx-drf-extensions # edx-toggles -edx-drf-extensions==8.8.0 +edx-drf-extensions==10.5.0 # via -r requirements/base.in -edx-opaque-keys==2.3.0 +edx-opaque-keys==2.11.0 # via edx-drf-extensions -edx-toggles==5.0.0 +edx-toggles==5.2.0 # via -r requirements/base.in -exceptiongroup==1.1.1 - # via - # anyio - # pytest -fastapi==0.95.2 +fastapi==0.115.6 # via pact-python fs==2.4.16 # via -r requirements/test.in h11==0.14.0 - # via - # httpcore - # uvicorn -httpcore==0.16.3 - # via httpx -httpx==0.23.1 - # via pact-python -idna==3.4 + # via uvicorn +idna==3.10 # via # anyio # requests - # rfc3986 + # yarl iniconfig==2.0.0 # via pytest -jinja2==3.1.2 +jinja2==3.1.4 # via code-annotations -lxml==4.9.2 +lxml==5.3.0 # via -r requirements/base.in -markupsafe==2.1.2 +markupsafe==3.0.2 # via jinja2 -mock==5.0.2 +mock==5.1.0 # via -r requirements/test.in -newrelic==8.8.0 +multidict==6.1.0 + # via yarl +newrelic==10.3.1 # via edx-django-utils -packaging==23.1 +packaging==24.2 # via pytest -pact-python==1.7.0 +pact-python==2.2.2 # via -r requirements/test.in -pbr==5.11.1 +pbr==6.1.0 # via stevedore -pillow==9.5.0 +pillow==11.0.0 # via -r requirements/base.in -pluggy==1.0.0 +pluggy==1.5.0 # via pytest -psutil==5.9.5 +propcache==0.2.1 + # via yarl +psutil==6.1.0 # via # edx-django-utils # pact-python -pycparser==2.21 +pycparser==2.22 # via cffi -pydantic==1.10.8 +pydantic==2.10.3 # via fastapi -pyjwt[crypto]==2.7.0 +pydantic-core==2.27.1 + # via pydantic +pyjwt[crypto]==2.10.1 # via # drf-jwt # edx-drf-extensions -pymongo==3.13.0 +pymongo==4.10.1 # via edx-opaque-keys pynacl==1.5.0 # via edx-django-utils pysrt==1.1.2 # via -r requirements/base.in -pytest==7.3.1 +pytest==8.3.4 # via # pytest-cov # pytest-django -pytest-cov==4.1.0 +pytest-cov==6.0.0 # via -r requirements/test.in -pytest-django==4.5.2 +pytest-django==4.9.0 # via -r requirements/test.in -python-dateutil==2.8.2 - # via edx-drf-extensions -python-slugify==8.0.1 +python-slugify==8.0.4 # via code-annotations -pytz==2023.3 - # via - # django - # djangorestframework -pyyaml==6.0 +pyyaml==6.0.2 # via # code-annotations # edx-django-release-util # responses -requests==2.31.0 +requests==2.32.3 # via # edx-drf-extensions # pact-python # responses -responses==0.23.1 +responses==0.25.3 # via -r requirements/test.in -rfc3986[idna2008]==1.5.0 - # via httpx semantic-version==2.10.0 # via edx-drf-extensions -six==1.16.0 +six==1.17.0 # via # edx-django-release-util - # edx-drf-extensions # fs # pact-python - # python-dateutil -sniffio==1.3.0 - # via - # anyio - # httpcore - # httpx -sqlparse==0.4.4 +sniffio==1.3.1 + # via anyio +sqlparse==0.5.2 # via django -starlette==0.27.0 +starlette==0.41.3 # via fastapi -stevedore==5.1.0 +stevedore==5.4.0 # via # code-annotations # edx-django-utils # edx-opaque-keys text-unidecode==1.3 # via python-slugify -tomli==2.0.1 +typing-extensions==4.12.2 # via - # coverage - # pytest -types-pyyaml==6.0.12.10 - # via responses -typing-extensions==4.6.3 - # via - # asgiref + # anyio + # edx-opaque-keys + # fastapi # pydantic - # starlette -urllib3==2.0.2 + # pydantic-core +urllib3==2.2.3 # via - # pact-python # requests # responses -uvicorn==0.22.0 +uvicorn==0.32.1 + # via pact-python +yarl==1.18.3 # via pact-python # The following packages are considered to be unsafe in a requirements file: diff --git a/setup.py b/setup.py index 23a2c1b5..cc31367f 100644 --- a/setup.py +++ b/setup.py @@ -148,9 +148,9 @@ def get_version(*file_paths): 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.11', 'Framework :: Django', - 'Framework :: Django :: 3.2', + 'Framework :: Django :: 4.2', ], packages=PACKAGES, install_requires=load_requirements('requirements/base.in'), diff --git a/tox.ini b/tox.ini index 196a5857..d78a48cc 100644 --- a/tox.ini +++ b/tox.ini @@ -1,22 +1,19 @@ [tox] -envlist = py38-django{32,42}, quality +envlist = py{38,311}-django{42}, quality [testenv] -deps = - django32: Django>=3.2,<4.0 - django40: Django>=4.0,<4.1 +deps = django42: Django>=4.2,<4.3 -r{toxinidir}/requirements/test.txt -commands = +commands = python -Wd -m pytest {posargs} [testenv:quality] -basepython = python3.8 -whitelist_externals = +allowlist_externals = make -deps = +deps = -r{toxinidir}/requirements/quality.txt -commands = +commands = pylint edxval pycodestyle edxval pydocstyle edxval @@ -24,4 +21,3 @@ commands = make selfcheck python setup.py sdist bdist_wheel twine check dist/* -