From afa102e125ca732493e77ab595dcf3fd15acce3b Mon Sep 17 00:00:00 2001 From: Usama Sadiq Date: Tue, 9 Mar 2021 12:54:42 +0500 Subject: [PATCH] refactor: ran pyupgrade on lms/djangoapps/course_api (#26735) --- lms/djangoapps/course_api/api.py | 20 +++--- lms/djangoapps/course_api/blocks/forms.py | 4 +- .../course_api/blocks/permissions.py | 8 ++- .../course_api/blocks/serializers.py | 19 +++--- .../course_api/blocks/tests/test_api.py | 45 +++++++------- .../course_api/blocks/tests/test_forms.py | 12 ++-- .../blocks/tests/test_serializers.py | 25 ++++---- .../course_api/blocks/tests/test_views.py | 18 +++--- lms/djangoapps/course_api/blocks/toggles.py | 4 +- .../blocks/transformers/blocks_api.py | 2 +- .../blocks/transformers/milestones.py | 13 ++-- .../blocks/transformers/navigation.py | 6 +- .../tests/test_block_completion.py | 4 +- .../transformers/tests/test_block_counts.py | 2 +- .../transformers/tests/test_extra_fields.py | 2 +- .../transformers/tests/test_milestones.py | 16 ++--- .../transformers/tests/test_navigation.py | 7 +-- .../transformers/tests/test_student_view.py | 2 +- .../transformers/tests/test_video_urls.py | 11 ++-- .../blocks/transformers/video_urls.py | 5 +- lms/djangoapps/course_api/blocks/urls.py | 4 +- lms/djangoapps/course_api/blocks/views.py | 10 ++- lms/djangoapps/course_api/forms.py | 7 +-- lms/djangoapps/course_api/serializers.py | 11 ++-- lms/djangoapps/course_api/tests/mixins.py | 6 +- lms/djangoapps/course_api/tests/test_api.py | 20 +++--- lms/djangoapps/course_api/tests/test_forms.py | 21 +++---- .../course_api/tests/test_permissions.py | 2 +- .../course_api/tests/test_serializers.py | 62 +++++++++---------- lms/djangoapps/course_api/tests/test_views.py | 36 +++++------ lms/djangoapps/course_api/urls.py | 2 +- lms/djangoapps/course_api/views.py | 16 ++--- 32 files changed, 205 insertions(+), 217 deletions(-) diff --git a/lms/djangoapps/course_api/api.py b/lms/djangoapps/course_api/api.py index cbc84c8309..d43aa3f53d 100644 --- a/lms/djangoapps/course_api/api.py +++ b/lms/djangoapps/course_api/api.py @@ -3,32 +3,30 @@ Course API """ import logging -from edx_django_utils.monitoring import function_trace -from edx_when.api import get_dates_for_course +import search from django.conf import settings from django.contrib.auth.models import AnonymousUser, User # lint-amnesty, pylint: disable=imported-auth-user from django.urls import reverse +from edx_django_utils.monitoring import function_trace +from edx_when.api import get_dates_for_course +from opaque_keys.edx.django.models import CourseKeyField from rest_framework.exceptions import PermissionDenied -import search -import six +from common.djangoapps.student.models import CourseAccessRole +from common.djangoapps.student.roles import GlobalStaff from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.courses import ( get_course_overview_with_access, get_courses, get_permission_for_course_about ) -from opaque_keys.edx.django.models import CourseKeyField # lint-amnesty, pylint: disable=wrong-import-order from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.lib.api.view_utils import LazySequence -from common.djangoapps.student.models import CourseAccessRole -from common.djangoapps.student.roles import GlobalStaff from xmodule.modulestore.django import modulestore from xmodule.modulestore.exceptions import ItemNotFoundError from .permissions import can_view_courses_for_username - logger = logging.getLogger(__name__) # pylint: disable=invalid-name @@ -100,7 +98,7 @@ def _filter_by_search(course_queryset, search_term): return LazySequence( ( course for course in course_queryset - if six.text_type(course.id) in search_courses_ids + if str(course.id) in search_courses_ids ), est_len=len(course_queryset) ) @@ -235,12 +233,12 @@ def get_due_dates(request, course_key, user): store = modulestore() due_dates = [] - for (block_key, date_type), date in six.iteritems(dates): + for (block_key, date_type), date in dates.items(): if date_type == 'due': try: block_display_name = store.get_item(block_key).display_name except ItemNotFoundError: - logger.exception('Failed to get block for due date item with key: {}'.format(block_key)) + logger.exception(f'Failed to get block for due date item with key: {block_key}') block_display_name = UNKNOWN_BLOCK_DISPLAY_NAME # get url to the block in the course diff --git a/lms/djangoapps/course_api/blocks/forms.py b/lms/djangoapps/course_api/blocks/forms.py index ee8ea5d77b..24c6476c25 100644 --- a/lms/djangoapps/course_api/blocks/forms.py +++ b/lms/djangoapps/course_api/blocks/forms.py @@ -48,7 +48,7 @@ class BlockListGetForm(Form): try: return int(value) except ValueError: - raise ValidationError("'{}' is not a valid depth value.".format(value)) # lint-amnesty, pylint: disable=raise-missing-from + raise ValidationError(f"'{value}' is not a valid depth value.") # lint-amnesty, pylint: disable=raise-missing-from def clean_requested_fields(self): """ @@ -83,7 +83,7 @@ class BlockListGetForm(Form): """ Return cleaned data, including additional requested fields. """ - cleaned_data = super(BlockListGetForm, self).clean() # lint-amnesty, pylint: disable=super-with-arguments + cleaned_data = super().clean() # Add additional requested_fields that are specified as separate # parameters, if they were requested. diff --git a/lms/djangoapps/course_api/blocks/permissions.py b/lms/djangoapps/course_api/blocks/permissions.py index c0bda84cfc..4b8e976aae 100644 --- a/lms/djangoapps/course_api/blocks/permissions.py +++ b/lms/djangoapps/course_api/blocks/permissions.py @@ -4,13 +4,15 @@ Encapsulates permissions checks for Course Blocks API from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user from opaque_keys.edx.keys import CourseKey +from common.djangoapps.student.models import CourseEnrollment +from common.djangoapps.student.roles import CourseStaffRole from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.access_response import AccessResponse from lms.djangoapps.courseware.access_utils import ACCESS_DENIED, ACCESS_GRANTED, check_public_access -from lms.djangoapps.courseware.exceptions import CourseRunNotFound from lms.djangoapps.courseware.courses import get_course -from common.djangoapps.student.models import CourseEnrollment -from common.djangoapps.student.roles import CourseStaffRole +from lms.djangoapps.courseware.exceptions import CourseRunNotFound +from openedx.core.djangoapps.content.course_overviews.models import \ + CourseOverview # lint-amnesty, pylint: disable=unused-import from xmodule.course_module import COURSE_VISIBILITY_PUBLIC diff --git a/lms/djangoapps/course_api/blocks/serializers.py b/lms/djangoapps/course_api/blocks/serializers.py index aa887b7122..a489fb2485 100644 --- a/lms/djangoapps/course_api/blocks/serializers.py +++ b/lms/djangoapps/course_api/blocks/serializers.py @@ -3,7 +3,6 @@ Serializers for Course Blocks related return objects. """ -import six from django.conf import settings from rest_framework import serializers from rest_framework.reverse import reverse @@ -12,13 +11,13 @@ from lms.djangoapps.course_blocks.transformers.visibility import VisibilityTrans from .transformers.block_completion import BlockCompletionTransformer from .transformers.block_counts import BlockCountsTransformer +from .transformers.extra_fields import ExtraFieldsTransformer from .transformers.milestones import MilestonesAndSpecialExamsTransformer from .transformers.navigation import BlockNavigationTransformer from .transformers.student_view import StudentViewTransformer -from .transformers.extra_fields import ExtraFieldsTransformer -class SupportedFieldType(object): +class SupportedFieldType: """ Metadata about fields supported by different transformers """ @@ -141,16 +140,16 @@ class BlockSerializer(serializers.Serializer): # pylint: disable=abstract-metho authorization_denial_message = block_structure.get_xblock_field(block_key, 'authorization_denial_message') data = { - 'id': six.text_type(block_key), - 'block_id': six.text_type(block_key.block_id), + 'id': str(block_key), + 'block_id': str(block_key.block_id), 'lms_web_url': reverse( 'jump_to', - kwargs={'course_id': six.text_type(block_key.course_key), 'location': six.text_type(block_key)}, + kwargs={'course_id': str(block_key.course_key), 'location': str(block_key)}, request=self.context['request'], ), 'student_view_url': reverse( 'render_xblock', - kwargs={'usage_key_string': six.text_type(block_key)}, + kwargs={'usage_key_string': str(block_key)}, request=self.context['request'], ), } @@ -158,7 +157,7 @@ class BlockSerializer(serializers.Serializer): # pylint: disable=abstract-metho if settings.FEATURES.get("ENABLE_LTI_PROVIDER") and 'lti_url' in self.context['requested_fields']: data['lti_url'] = reverse( 'lti_provider_launch', - kwargs={'course_id': six.text_type(block_key.course_key), 'usage_id': six.text_type(block_key)}, + kwargs={'course_id': str(block_key.course_key), 'usage_id': str(block_key)}, request=self.context['request'], ) @@ -178,7 +177,7 @@ class BlockSerializer(serializers.Serializer): # pylint: disable=abstract-metho if 'children' in self.context['requested_fields']: children = block_structure.get_children(block_key) if children: - data['children'] = [six.text_type(child) for child in children] + data['children'] = [str(child) for child in children] if authorization_denial_reason and authorization_denial_message: data['authorization_denial_reason'] = authorization_denial_reason @@ -205,6 +204,6 @@ class BlockDictSerializer(serializers.Serializer): # pylint: disable=abstract-m Serialize to a dictionary of blocks keyed by the block's usage_key. """ return { - six.text_type(block_key): BlockSerializer(block_key, context=self.context).data + str(block_key): BlockSerializer(block_key, context=self.context).data for block_key in structure } diff --git a/lms/djangoapps/course_api/blocks/tests/test_api.py b/lms/djangoapps/course_api/blocks/tests/test_api.py index 1f060a38ef..a1e04fb714 100644 --- a/lms/djangoapps/course_api/blocks/tests/test_api.py +++ b/lms/djangoapps/course_api/blocks/tests/test_api.py @@ -4,20 +4,19 @@ Tests for Blocks api.py from itertools import product +from unittest.mock import patch import ddt -import six from django.test.client import RequestFactory from edx_toggles.toggles.testutils import override_waffle_switch -from mock import patch from common.djangoapps.student.tests.factories import UserFactory +from openedx.core.djangoapps.content.block_structure.api import clear_course_from_cache +from openedx.core.djangoapps.content.block_structure.config import STORAGE_BACKING_FOR_CACHE from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import SampleCourseFactory, check_mongo_calls from xmodule.modulestore.tests.sample_courses import BlockInfo -from openedx.core.djangoapps.content.block_structure.api import clear_course_from_cache -from openedx.core.djangoapps.content.block_structure.config import STORAGE_BACKING_FOR_CACHE from ..api import get_blocks @@ -29,7 +28,7 @@ class TestGetBlocks(SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(TestGetBlocks, cls).setUpClass() + super().setUpClass() with cls.store.default_store(ModuleStoreEnum.Type.split): cls.course = SampleCourseFactory.create() @@ -39,22 +38,22 @@ class TestGetBlocks(SharedModuleStoreTestCase): cls.store.update_item(cls.html_block, ModuleStoreEnum.UserID.test) def setUp(self): - super(TestGetBlocks, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create() self.request = RequestFactory().get("/dummy") self.request.user = self.user def test_basic(self): blocks = get_blocks(self.request, self.course.location, self.user) - assert blocks['root'] == six.text_type(self.course.location) + assert blocks['root'] == str(self.course.location) # subtract for (1) the orphaned course About block and (2) the hidden Html block assert len(blocks['blocks']) == (len(self.store.get_items(self.course.id)) - 2) - assert six.text_type(self.html_block.location) not in blocks['blocks'] + assert str(self.html_block.location) not in blocks['blocks'] def test_no_user(self): blocks = get_blocks(self.request, self.course.location) - assert six.text_type(self.html_block.location) in blocks['blocks'] + assert str(self.html_block.location) in blocks['blocks'] def test_access_before_api_transformer_order(self): """ @@ -65,16 +64,16 @@ class TestGetBlocks(SharedModuleStoreTestCase): vertical_block = self.store.get_item(self.course.id.make_usage_key('vertical', 'vertical_x1a')) problem_block = self.store.get_item(self.course.id.make_usage_key('problem', 'problem_x1a_1')) - vertical_descendants = blocks['blocks'][six.text_type(vertical_block.location)]['descendants'] + vertical_descendants = blocks['blocks'][str(vertical_block.location)]['descendants'] - assert six.text_type(problem_block.location) in vertical_descendants - assert six.text_type(self.html_block.location) not in vertical_descendants + assert str(problem_block.location) in vertical_descendants + assert str(self.html_block.location) not in vertical_descendants def test_sub_structure(self): sequential_block = self.store.get_item(self.course.id.make_usage_key('sequential', 'sequential_y1')) blocks = get_blocks(self.request, sequential_block.location, self.user) - assert blocks['root'] == six.text_type(sequential_block.location) + assert blocks['root'] == str(sequential_block.location) assert len(blocks['blocks']) == 5 for block_type, block_name, is_inside_of_structure in ( @@ -85,9 +84,9 @@ class TestGetBlocks(SharedModuleStoreTestCase): ): block = self.store.get_item(self.course.id.make_usage_key(block_type, block_name)) if is_inside_of_structure: - assert six.text_type(block.location) in blocks['blocks'] + assert str(block.location) in blocks['blocks'] else: - assert six.text_type(block.location) not in blocks['blocks'] + assert str(block.location) not in blocks['blocks'] def test_filtering_by_block_types(self): sequential_block = self.store.get_item(self.course.id.make_usage_key('sequential', 'sequential_y1')) @@ -96,7 +95,7 @@ class TestGetBlocks(SharedModuleStoreTestCase): blocks = get_blocks(self.request, sequential_block.location, self.user, requested_fields=['type']) assert len(blocks['blocks']) == 5 found_not_problem = False - for block in six.itervalues(blocks['blocks']): + for block in blocks['blocks'].values(): if block['type'] != 'problem': found_not_problem = True assert found_not_problem @@ -105,7 +104,7 @@ class TestGetBlocks(SharedModuleStoreTestCase): blocks = get_blocks(self.request, sequential_block.location, self.user, block_types_filter=['problem'], requested_fields=['type']) assert len(blocks['blocks']) == 3 - for block in six.itervalues(blocks['blocks']): + for block in blocks['blocks'].values(): assert block['type'] == 'problem' @@ -118,7 +117,7 @@ class TestGetBlocksMobileHack(SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(TestGetBlocksMobileHack, cls).setUpClass() + super().setUpClass() with cls.store.default_store(ModuleStoreEnum.Type.split): cls.course = SampleCourseFactory.create( block_info_tree=[ @@ -139,7 +138,7 @@ class TestGetBlocksMobileHack(SharedModuleStoreTestCase): ) def setUp(self): - super(TestGetBlocksMobileHack, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create() self.request = RequestFactory().get("/dummy") self.request.user = self.user @@ -151,9 +150,9 @@ class TestGetBlocksMobileHack(SharedModuleStoreTestCase): def test_empty_containers(self, is_mobile, container_type): with patch('lms.djangoapps.course_api.blocks.api.is_request_from_mobile_app', return_value=is_mobile): blocks = get_blocks(self.request, self.course.location) - full_container_key = self.course.id.make_usage_key(container_type, 'full_{}'.format(container_type)) + full_container_key = self.course.id.make_usage_key(container_type, f'full_{container_type}') assert str(full_container_key) in blocks['blocks'] - empty_container_key = self.course.id.make_usage_key(container_type, 'empty_{}'.format(container_type)) + empty_container_key = self.course.id.make_usage_key(container_type, f'empty_{container_type}') assert_containment = self.assertNotIn if is_mobile else self.assertIn assert_containment(str(empty_container_key), blocks['blocks']) @@ -180,7 +179,7 @@ class TestGetBlocksMobileHack(SharedModuleStoreTestCase): ) video_block_key = str(self.course.id.make_usage_key('video', 'sample_video')) video_block_data = blocks['blocks'][video_block_key] - for video_data in six.itervalues(video_block_data['student_view_data']['encoded_videos']): + for video_data in video_block_data['student_view_data']['encoded_videos'].values(): assert 'cloudfront' not in video_data['url'] @@ -193,7 +192,7 @@ class TestGetBlocksQueryCountsBase(SharedModuleStoreTestCase): ENABLED_SIGNALS = ['course_published'] def setUp(self): - super(TestGetBlocksQueryCountsBase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create() self.request = RequestFactory().get("/dummy") diff --git a/lms/djangoapps/course_api/blocks/tests/test_forms.py b/lms/djangoapps/course_api/blocks/tests/test_forms.py index 1def5ce120..683a384e7a 100644 --- a/lms/djangoapps/course_api/blocks/tests/test_forms.py +++ b/lms/djangoapps/course_api/blocks/tests/test_forms.py @@ -3,17 +3,17 @@ Tests for Course Blocks forms """ +from urllib.parse import urlencode + import ddt import pytest -import six -from six.moves.urllib.parse import urlencode from django.http import Http404, QueryDict from opaque_keys.edx.locator import CourseLocator from rest_framework.exceptions import PermissionDenied -from openedx.core.djangoapps.util.test_forms import FormTestMixin from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory +from openedx.core.djangoapps.util.test_forms import FormTestMixin from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -30,12 +30,12 @@ class TestBlockListGetForm(FormTestMixin, SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(TestBlockListGetForm, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() def setUp(self): - super(TestBlockListGetForm, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.student = UserFactory.create() self.student2 = UserFactory.create() @@ -49,7 +49,7 @@ class TestBlockListGetForm(FormTestMixin, SharedModuleStoreTestCase): self.form_data = QueryDict( urlencode({ 'username': self.student.username, - 'usage_key': six.text_type(usage_key), + 'usage_key': str(usage_key), }), mutable=True, ) diff --git a/lms/djangoapps/course_api/blocks/tests/test_serializers.py b/lms/djangoapps/course_api/blocks/tests/test_serializers.py index 0f53fb7aab..77e141cc5b 100644 --- a/lms/djangoapps/course_api/blocks/tests/test_serializers.py +++ b/lms/djangoapps/course_api/blocks/tests/test_serializers.py @@ -3,13 +3,12 @@ Tests for Course Blocks serializers """ -import six -from mock import MagicMock +from unittest.mock import MagicMock -from lms.djangoapps.course_blocks.api import get_course_block_access_transformers, get_course_blocks -from openedx.core.djangoapps.content.block_structure.transformers import BlockStructureTransformers from common.djangoapps.student.roles import CourseStaffRole from common.djangoapps.student.tests.factories import UserFactory +from lms.djangoapps.course_blocks.api import get_course_block_access_transformers, get_course_blocks +from openedx.core.djangoapps.content.block_structure.transformers import BlockStructureTransformers from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import ToyCourseFactory @@ -26,7 +25,7 @@ class TestBlockSerializerBase(SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(TestBlockSerializerBase, cls).setUpClass() + super().setUpClass() cls.course = ToyCourseFactory.create() @@ -37,7 +36,7 @@ class TestBlockSerializerBase(SharedModuleStoreTestCase): cls.store.update_item(cls.html_block, ModuleStoreEnum.UserID.test) def setUp(self): - super(TestBlockSerializerBase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create() @@ -65,7 +64,7 @@ class TestBlockSerializerBase(SharedModuleStoreTestCase): """ block_key = deserialize_usage_key(block_key_string, self.course.id) assert self.block_structure.get_xblock_field(block_key, 'category') == serialized_block['type'] - assert set(six.iterkeys(serialized_block)) == {'id', 'block_id', 'type', 'lms_web_url', 'student_view_url'} + assert set(serialized_block.keys()) == {'id', 'block_id', 'type', 'lms_web_url', 'student_view_url'} def add_additional_requested_fields(self, context=None): """ @@ -90,7 +89,7 @@ class TestBlockSerializerBase(SharedModuleStoreTestCase): Verifies the given serialized_block when additional fields are requested. """ assert {'id', 'type', 'lms_web_url', 'student_view_url', 'display_name', 'graded', 'student_view_multi_device', - 'lti_url', 'visible_to_staff_only'} <= set(six.iterkeys(serialized_block)) + 'lti_url', 'visible_to_staff_only'} <= set(serialized_block.keys()) # video blocks should have student_view_data if serialized_block['type'] == 'video': @@ -131,7 +130,7 @@ class TestBlockSerializerBase(SharedModuleStoreTestCase): """ Test fields accessed by a staff user """ - if serialized_block['id'] == six.text_type(self.html_block.location): + if serialized_block['id'] == str(self.html_block.location): assert serialized_block['visible_to_staff_only'] else: assert not serialized_block['visible_to_staff_only'] @@ -197,10 +196,10 @@ class TestBlockDictSerializer(TestBlockSerializerBase): serializer = self.create_serializer() # verify root - assert serializer.data['root'] == six.text_type(self.block_structure.root_block_usage_key) + assert serializer.data['root'] == str(self.block_structure.root_block_usage_key) # verify blocks - for block_key_string, serialized_block in six.iteritems(serializer.data['blocks']): + for block_key_string, serialized_block in serializer.data['blocks'].items(): assert serialized_block['id'] == block_key_string self.assert_basic_block(block_key_string, serialized_block) assert len(serializer.data['blocks']) == 28 @@ -208,7 +207,7 @@ class TestBlockDictSerializer(TestBlockSerializerBase): def test_additional_requested_fields(self): self.add_additional_requested_fields() serializer = self.create_serializer() - for serialized_block in six.itervalues(serializer.data['blocks']): + for serialized_block in serializer.data['blocks'].values(): self.assert_extended_block(serialized_block) assert len(serializer.data['blocks']) == 28 @@ -219,7 +218,7 @@ class TestBlockDictSerializer(TestBlockSerializerBase): context = self.create_staff_context() self.add_additional_requested_fields(context) serializer = self.create_serializer(context) - for serialized_block in six.itervalues(serializer.data['blocks']): + for serialized_block in serializer.data['blocks'].values(): self.assert_extended_block(serialized_block) self.assert_staff_fields(serialized_block) assert len(serializer.data['blocks']) == 29 diff --git a/lms/djangoapps/course_api/blocks/tests/test_views.py b/lms/djangoapps/course_api/blocks/tests/test_views.py index 77f1d9ac4c..426e79c668 100644 --- a/lms/djangoapps/course_api/blocks/tests/test_views.py +++ b/lms/djangoapps/course_api/blocks/tests/test_views.py @@ -8,10 +8,10 @@ from unittest import mock from unittest.mock import Mock from urllib.parse import urlencode, urlunparse +from completion.test_utils import CompletionWaffleTestMixin, submit_completions_for_testing from django.conf import settings from django.urls import reverse from opaque_keys.edx.locator import CourseLocator -from completion.test_utils import CompletionWaffleTestMixin, submit_completions_for_testing from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.tests.factories import AdminFactory, CourseEnrollmentFactory, UserFactory @@ -30,7 +30,7 @@ class TestBlocksView(SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(TestBlocksView, cls).setUpClass() + super().setUpClass() # create a toy course cls.course = ToyCourseFactory.create( @@ -40,15 +40,15 @@ class TestBlocksView(SharedModuleStoreTestCase): cls.course_key = cls.course.id cls.course_usage_key = cls.store.make_course_usage_key(cls.course_key) - cls.non_orphaned_block_usage_keys = set( + cls.non_orphaned_block_usage_keys = { str(item.location) for item in cls.store.get_items(cls.course_key) # remove all orphaned items in the course, except for the root 'course' block if cls.store.get_parent_location(item.location) or item.category == 'course' - ) + } def setUp(self): - super(TestBlocksView, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # create and enroll user in the toy course self.user = UserFactory.create() @@ -126,7 +126,7 @@ class TestBlocksView(SharedModuleStoreTestCase): if xblock.has_children: self.assertSetEqual( - set(str(child.location) for child in xblock.get_children()), + {str(child.location) for child in xblock.get_children()}, set(block_data['children']), ) @@ -390,16 +390,16 @@ class TestBlocksInCourseView(TestBlocksView, CompletionWaffleTestMixin): # pyli """ def setUp(self): - super(TestBlocksInCourseView, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse('blocks_in_course') self.query_params['course_id'] = str(self.course_key) self.override_waffle_switch(True) - self.non_orphaned_raw_block_usage_keys = set( + self.non_orphaned_raw_block_usage_keys = { item.location for item in self.store.get_items(self.course_key) # remove all orphaned items in the course, except for the root 'course' block if self.store.get_parent_location(item.location) or item.category == 'course' - ) + } def test_no_course_id(self): self.query_params.pop('course_id') diff --git a/lms/djangoapps/course_api/blocks/toggles.py b/lms/djangoapps/course_api/blocks/toggles.py index f1dda2fdda..a2e2f900b0 100644 --- a/lms/djangoapps/course_api/blocks/toggles.py +++ b/lms/djangoapps/course_api/blocks/toggles.py @@ -5,7 +5,7 @@ Toggles for Course API. from edx_toggles.toggles import LegacyWaffleFlag, LegacyWaffleFlagNamespace -COURSE_BLOCKS_API_NAMESPACE = LegacyWaffleFlagNamespace(name=u'course_blocks_api') +COURSE_BLOCKS_API_NAMESPACE = LegacyWaffleFlagNamespace(name='course_blocks_api') # .. toggle_name: course_blocks_api.hide_access_denials # .. toggle_implementation: WaffleFlag @@ -18,6 +18,6 @@ COURSE_BLOCKS_API_NAMESPACE = LegacyWaffleFlagNamespace(name=u'course_blocks_api # .. toggle_tickets: None HIDE_ACCESS_DENIALS_FLAG = LegacyWaffleFlag( waffle_namespace=COURSE_BLOCKS_API_NAMESPACE, - flag_name=u'hide_access_denials', + flag_name='hide_access_denials', module_name=__name__, ) diff --git a/lms/djangoapps/course_api/blocks/transformers/blocks_api.py b/lms/djangoapps/course_api/blocks/transformers/blocks_api.py index bd733a9cfb..2d2345b0a8 100644 --- a/lms/djangoapps/course_api/blocks/transformers/blocks_api.py +++ b/lms/djangoapps/course_api/blocks/transformers/blocks_api.py @@ -7,10 +7,10 @@ from openedx.core.djangoapps.content.block_structure.transformer import BlockStr from .block_counts import BlockCountsTransformer from .block_depth import BlockDepthTransformer +from .extra_fields import ExtraFieldsTransformer from .navigation import BlockNavigationTransformer from .student_view import StudentViewTransformer from .video_urls import VideoBlockURLTransformer -from .extra_fields import ExtraFieldsTransformer class BlocksAPITransformer(BlockStructureTransformer): diff --git a/lms/djangoapps/course_api/blocks/transformers/milestones.py b/lms/djangoapps/course_api/blocks/transformers/milestones.py index fc4047be48..5179f989e8 100644 --- a/lms/djangoapps/course_api/blocks/transformers/milestones.py +++ b/lms/djangoapps/course_api/blocks/transformers/milestones.py @@ -5,14 +5,13 @@ Milestones Transformer import logging -import six from django.conf import settings from edx_proctoring.api import get_attempt_status_summary from edx_proctoring.exceptions import ProctoredExamNotFoundException -from openedx.core.djangoapps.content.block_structure.transformer import BlockStructureTransformer from common.djangoapps.student.models import EntranceExamConfiguration from common.djangoapps.util import milestones_helpers +from openedx.core.djangoapps.content.block_structure.transformer import BlockStructureTransformer log = logging.getLogger(__name__) @@ -102,8 +101,8 @@ class MilestonesAndSpecialExamsTransformer(BlockStructureTransformer): them from accessing this block. """ return bool(milestones_helpers.get_course_content_milestones( - six.text_type(block_key.course_key), - six.text_type(block_key), + str(block_key.course_key), + str(block_key), 'requires', usage_info.user.id )) @@ -120,8 +119,8 @@ class MilestonesAndSpecialExamsTransformer(BlockStructureTransformer): # This will return None, if (user, course_id, content_id) is not applicable. special_exam_attempt_context = get_attempt_status_summary( usage_info.user.id, - six.text_type(block_key.course_key), - six.text_type(block_key) + str(block_key.course_key), + str(block_key) ) except ProctoredExamNotFoundException as ex: log.exception(ex) @@ -169,7 +168,7 @@ class MilestonesAndSpecialExamsTransformer(BlockStructureTransformer): if not required_content: return False - if block_key.block_type == 'chapter' and six.text_type(block_key) not in required_content: + if block_key.block_type == 'chapter' and str(block_key) not in required_content: return True return False diff --git a/lms/djangoapps/course_api/blocks/transformers/navigation.py b/lms/djangoapps/course_api/blocks/transformers/navigation.py index edf0331390..8b1e9f62e7 100644 --- a/lms/djangoapps/course_api/blocks/transformers/navigation.py +++ b/lms/djangoapps/course_api/blocks/transformers/navigation.py @@ -3,14 +3,12 @@ TODO """ -import six - from openedx.core.djangoapps.content.block_structure.transformer import BlockStructureTransformer from .block_depth import BlockDepthTransformer -class DescendantList(object): +class DescendantList: """ Contain """ @@ -76,7 +74,7 @@ class BlockNavigationTransformer(BlockStructureTransformer): # add self to parent's descendants for parent_desc_list in parents_descendants_list: if parent_desc_list is not None: - parent_desc_list.items.append(six.text_type(block_key)) + parent_desc_list.items.append(str(block_key)) if BlockDepthTransformer.get_block_depth(block_structure, block_key) > self.nav_depth: children_descendants_list = parents_descendants_list diff --git a/lms/djangoapps/course_api/blocks/transformers/tests/test_block_completion.py b/lms/djangoapps/course_api/blocks/transformers/tests/test_block_completion.py index d66f3bddf6..b5d872510a 100644 --- a/lms/djangoapps/course_api/blocks/transformers/tests/test_block_completion.py +++ b/lms/djangoapps/course_api/blocks/transformers/tests/test_block_completion.py @@ -8,10 +8,10 @@ from completion.test_utils import CompletionWaffleTestMixin from xblock.completable import CompletableXBlockMixin, XBlockCompletionMode from xblock.core import XBlock +from common.djangoapps.student.tests.factories import UserFactory from lms.djangoapps.course_api.blocks.transformers.block_completion import BlockCompletionTransformer from lms.djangoapps.course_blocks.api import get_course_blocks from lms.djangoapps.course_blocks.transformers.tests.helpers import ModuleStoreTestCase, TransformerRegistryTestMixin -from common.djangoapps.student.tests.factories import UserFactory from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory @@ -47,7 +47,7 @@ class BlockCompletionTransformerTestCase(TransformerRegistryTestMixin, Completio COMPLETION_TEST_VALUE = 0.4 def setUp(self): - super(BlockCompletionTransformerTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create(password='test') # Set ENABLE_COMPLETION_TRACKING waffle switch to True self.override_waffle_switch(True) diff --git a/lms/djangoapps/course_api/blocks/transformers/tests/test_block_counts.py b/lms/djangoapps/course_api/blocks/transformers/tests/test_block_counts.py index 12a97b7206..bfd2ea4a3e 100644 --- a/lms/djangoapps/course_api/blocks/transformers/tests/test_block_counts.py +++ b/lms/djangoapps/course_api/blocks/transformers/tests/test_block_counts.py @@ -18,7 +18,7 @@ class TestBlockCountsTransformer(ModuleStoreTestCase): """ def setUp(self): - super(TestBlockCountsTransformer, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course_key = SampleCourseFactory.create().id self.course_usage_key = self.store.make_course_usage_key(self.course_key) self.block_structure = BlockStructureFactory.create_from_modulestore(self.course_usage_key, self.store) diff --git a/lms/djangoapps/course_api/blocks/transformers/tests/test_extra_fields.py b/lms/djangoapps/course_api/blocks/transformers/tests/test_extra_fields.py index 293aae25a8..0fee9166dd 100644 --- a/lms/djangoapps/course_api/blocks/transformers/tests/test_extra_fields.py +++ b/lms/djangoapps/course_api/blocks/transformers/tests/test_extra_fields.py @@ -30,7 +30,7 @@ class TestExtraFieldsTransformer(ModuleStoreTestCase): } def setUp(self): - super(TestExtraFieldsTransformer, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = SampleCourseFactory.create( other_course_settings=self.OTHER_COURSE_SETTINGS_DEFAULT diff --git a/lms/djangoapps/course_api/blocks/transformers/tests/test_milestones.py b/lms/djangoapps/course_api/blocks/transformers/tests/test_milestones.py index 7ef66fd8cb..f2679bd11b 100644 --- a/lms/djangoapps/course_api/blocks/transformers/tests/test_milestones.py +++ b/lms/djangoapps/course_api/blocks/transformers/tests/test_milestones.py @@ -3,17 +3,17 @@ Tests for ProctoredExamTransformer. """ -import ddt -import six -from milestones.tests.utils import MilestonesTestCaseMixin -from mock import Mock, patch +from unittest.mock import Mock, patch -from lms.djangoapps.gating import api as lms_gating_api +import ddt +from milestones.tests.utils import MilestonesTestCaseMixin + +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory from lms.djangoapps.course_blocks.api import get_course_blocks from lms.djangoapps.course_blocks.transformers.tests.helpers import CourseStructureTestCase +from lms.djangoapps.gating import api as lms_gating_api from openedx.core.djangoapps.content.block_structure.transformers import BlockStructureTransformers from openedx.core.lib.gating import api as gating_api -from common.djangoapps.student.tests.factories import CourseEnrollmentFactory from ..milestones import MilestonesAndSpecialExamsTransformer @@ -30,7 +30,7 @@ class MilestonesTransformerTestCase(CourseStructureTestCase, MilestonesTestCaseM """ Setup course structure and create user for split test transformer test. """ - super(MilestonesTransformerTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # Build course. self.course_hierarchy = self.get_course_hierarchy() @@ -49,7 +49,7 @@ class MilestonesTransformerTestCase(CourseStructureTestCase, MilestonesTestCaseM gated_block: The block that should be inaccessible until gating_block is completed gating_block: The block that must be completed before access is granted """ - gating_api.add_prerequisite(self.course.id, six.text_type(gating_block.location)) + gating_api.add_prerequisite(self.course.id, str(gating_block.location)) gating_api.set_required_content(self.course.id, gated_block.location, gating_block.location, 100, 0) ALL_BLOCKS = ( diff --git a/lms/djangoapps/course_api/blocks/transformers/tests/test_navigation.py b/lms/djangoapps/course_api/blocks/transformers/tests/test_navigation.py index 1e11fa24dd..6d1110d678 100644 --- a/lms/djangoapps/course_api/blocks/transformers/tests/test_navigation.py +++ b/lms/djangoapps/course_api/blocks/transformers/tests/test_navigation.py @@ -7,7 +7,6 @@ Tests for BlockNavigationTransformer. from unittest import TestCase import ddt -import six from lms.djangoapps.course_api.blocks.transformers.block_depth import BlockDepthTransformer from lms.djangoapps.course_api.blocks.transformers.navigation import BlockNavigationTransformer @@ -57,7 +56,7 @@ class BlockNavigationTransformerTestCase(TestCase, ChildrenMapTestMixin): for block_key, expected_nav in enumerate(expected_nav_map): self.assertSetEqual( - set(six.text_type(block) for block in expected_nav), + {str(block) for block in expected_nav}, set( block_structure.get_transformer_block_field( block_key, @@ -114,7 +113,7 @@ class BlockNavigationTransformerCourseTestCase(ModuleStoreTestCase): course_key.make_usage_key('vertical', 'vertical_y1a'), course_key.make_usage_key('problem', 'problem_y1a_1'), ]: - assert six.text_type(block_key) in course_descendants + assert str(block_key) in course_descendants # chapter_x and its descendants should not be included for block_key in [ @@ -123,4 +122,4 @@ class BlockNavigationTransformerCourseTestCase(ModuleStoreTestCase): course_key.make_usage_key('vertical', 'vertical_x1a'), course_key.make_usage_key('problem', 'problem_x1a_1'), ]: - assert six.text_type(block_key) not in course_descendants + assert str(block_key) not in course_descendants diff --git a/lms/djangoapps/course_api/blocks/transformers/tests/test_student_view.py b/lms/djangoapps/course_api/blocks/transformers/tests/test_student_view.py index b492ed0429..91977c0c77 100644 --- a/lms/djangoapps/course_api/blocks/transformers/tests/test_student_view.py +++ b/lms/djangoapps/course_api/blocks/transformers/tests/test_student_view.py @@ -20,7 +20,7 @@ class TestStudentViewTransformer(ModuleStoreTestCase): """ def setUp(self): - super(TestStudentViewTransformer, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course_key = ToyCourseFactory.create().id self.course_usage_key = self.store.make_course_usage_key(self.course_key) self.block_structure = BlockStructureFactory.create_from_modulestore(self.course_usage_key, self.store) diff --git a/lms/djangoapps/course_api/blocks/transformers/tests/test_video_urls.py b/lms/djangoapps/course_api/blocks/transformers/tests/test_video_urls.py index c877703b70..bd327d0cc3 100644 --- a/lms/djangoapps/course_api/blocks/transformers/tests/test_video_urls.py +++ b/lms/djangoapps/course_api/blocks/transformers/tests/test_video_urls.py @@ -3,8 +3,7 @@ Tests for VideoBlockURLTransformer. """ -import mock -import six +from unittest import mock from openedx.core.djangoapps.content.block_structure.factory import BlockStructureFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase @@ -20,7 +19,7 @@ class TestVideoBlockURLTransformer(ModuleStoreTestCase): """ def setUp(self): - super(TestVideoBlockURLTransformer, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course_key = ToyCourseFactory.create().id self.course_usage_key = self.store.make_course_usage_key(self.course_key) self.block_structure = BlockStructureFactory.create_from_modulestore(self.course_usage_key, self.store) @@ -37,7 +36,7 @@ class TestVideoBlockURLTransformer(ModuleStoreTestCase): Relocate url data in new dictionary for pre & post transformation data comparison. """ video_urls = {} - for video_format, video_data in six.iteritems(encoded_videos): + for video_format, video_data in encoded_videos.items(): video_urls[video_format] = video_data['url'] return video_urls @@ -91,7 +90,7 @@ class TestVideoBlockURLTransformer(ModuleStoreTestCase): post_transform_data = self.get_post_transform_data(video_block_key) post_transform_data = self.change_encoded_videos_presentation(post_transform_data['encoded_videos']) - for video_format, video_url in six.iteritems(post_transform_data): + for video_format, video_url in post_transform_data.items(): assert pre_transform_data[video_format] != video_url @mock.patch('xmodule.video_module.VideoBlock.student_view_data') @@ -121,7 +120,7 @@ class TestVideoBlockURLTransformer(ModuleStoreTestCase): post_transform_data = self.get_post_transform_data(video_block_key) post_transform_data = self.change_encoded_videos_presentation(post_transform_data['encoded_videos']) - for video_format, video_url in six.iteritems(post_transform_data): + for video_format, video_url in post_transform_data.items(): assert pre_transform_data[video_format] == video_url @mock.patch('xmodule.video_module.VideoBlock.student_view_data') diff --git a/lms/djangoapps/course_api/blocks/transformers/video_urls.py b/lms/djangoapps/course_api/blocks/transformers/video_urls.py index 0f2b611362..843aa9fa3f 100644 --- a/lms/djangoapps/course_api/blocks/transformers/video_urls.py +++ b/lms/djangoapps/course_api/blocks/transformers/video_urls.py @@ -3,11 +3,10 @@ Video block URL Transformer """ -import six from django.conf import settings -from xmodule.video_module.video_utils import rewrite_video_url from openedx.core.djangoapps.content.block_structure.transformer import BlockStructureTransformer +from xmodule.video_module.video_utils import rewrite_video_url from .student_view import StudentViewTransformer @@ -52,7 +51,7 @@ class VideoBlockURLTransformer(BlockStructureTransformer): if only_on_web: continue encoded_videos = student_view_data.get('encoded_videos') - for video_format, video_data in six.iteritems(encoded_videos): + for video_format, video_data in encoded_videos.items(): if video_format in self.VIDEO_FORMAT_EXCEPTIONS: continue video_data['url'] = rewrite_video_url(self.CDN_URL, video_data['url']) diff --git a/lms/djangoapps/course_api/blocks/urls.py b/lms/djangoapps/course_api/blocks/urls.py index 60a96ea47c..e5f684aa42 100644 --- a/lms/djangoapps/course_api/blocks/urls.py +++ b/lms/djangoapps/course_api/blocks/urls.py @@ -11,7 +11,7 @@ from .views import BlocksInCourseView, BlocksView urlpatterns = [ # This endpoint requires the usage_key for the starting block. url( - r'^v1/blocks/{}'.format(settings.USAGE_KEY_PATTERN), + fr'^v1/blocks/{settings.USAGE_KEY_PATTERN}', BlocksView.as_view(), kwargs={'hide_access_denials': True}, name="blocks_in_block_tree" @@ -26,7 +26,7 @@ urlpatterns = [ ), # This endpoint requires the usage_key for the starting block. url( - r'^v2/blocks/{}'.format(settings.USAGE_KEY_PATTERN), + fr'^v2/blocks/{settings.USAGE_KEY_PATTERN}', BlocksView.as_view(), name="blocks_in_block_tree" ), diff --git a/lms/djangoapps/course_api/blocks/views.py b/lms/djangoapps/course_api/blocks/views.py index 83d62d1853..edc5564de0 100644 --- a/lms/djangoapps/course_api/blocks/views.py +++ b/lms/djangoapps/course_api/blocks/views.py @@ -3,7 +3,6 @@ CourseBlocks API views """ -import six from django.core.exceptions import ValidationError from django.db import transaction from django.http import Http404 @@ -13,7 +12,6 @@ from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from rest_framework.generics import ListAPIView from rest_framework.response import Response -from six import text_type from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin, view_auth_classes from xmodule.modulestore.django import modulestore @@ -238,7 +236,7 @@ class BlocksView(DeveloperErrorViewMixin, ListAPIView): patch_response_headers(response) return response except ItemNotFoundError as exception: - raise Http404(u"Block not found: {}".format(text_type(exception))) # lint-amnesty, pylint: disable=raise-missing-from + raise Http404("Block not found: {}".format(str(exception))) # lint-amnesty, pylint: disable=raise-missing-from @view_auth_classes(is_authenticated=False) @@ -301,9 +299,9 @@ class BlocksInCourseView(BlocksView): course_key = CourseKey.from_string(course_key_string) course_usage_key = modulestore().make_course_usage_key(course_key) except InvalidKeyError: - raise ValidationError(u"'{}' is not a valid course key.".format(six.text_type(course_key_string))) # lint-amnesty, pylint: disable=raise-missing-from + raise ValidationError("'{}' is not a valid course key.".format(str(course_key_string))) # lint-amnesty, pylint: disable=raise-missing-from response = super().list(request, course_usage_key, - hide_access_denials=hide_access_denials) # lint-amnesty, pylint: disable=super-with-arguments + hide_access_denials=hide_access_denials) calculate_completion = any('completion' in param for param in request.query_params.getlist('requested_fields', [])) @@ -323,7 +321,7 @@ class BlocksInCourseView(BlocksView): course_blocks = response.data['blocks'] if not root: - raise ValueError("Unable to find course block in {}".format(course_key_string)) + raise ValueError(f"Unable to find course block in {course_key_string}") recurse_mark_complete(root, course_blocks) return response diff --git a/lms/djangoapps/course_api/forms.py b/lms/djangoapps/course_api/forms.py index ae30938ca4..f9843f63c0 100644 --- a/lms/djangoapps/course_api/forms.py +++ b/lms/djangoapps/course_api/forms.py @@ -5,7 +5,6 @@ Course API forms from collections import namedtuple -import six from django.core.exceptions import ValidationError from django.forms import CharField, Form from opaque_keys import InvalidKeyError @@ -14,7 +13,7 @@ from opaque_keys.edx.keys import CourseKey from openedx.core.djangoapps.util.forms import ExtendedNullBooleanField -class UsernameValidatorMixin(object): +class UsernameValidatorMixin: """ Mixin class for validating the username parameter. """ @@ -43,7 +42,7 @@ class CourseDetailGetForm(UsernameValidatorMixin, Form): try: return CourseKey.from_string(course_key_string) except InvalidKeyError: - raise ValidationError(u"'{}' is not a valid course key.".format(six.text_type(course_key_string))) # lint-amnesty, pylint: disable=raise-missing-from + raise ValidationError("'{}' is not a valid course key.".format(str(course_key_string))) # lint-amnesty, pylint: disable=raise-missing-from class CourseListGetForm(UsernameValidatorMixin, Form): @@ -65,7 +64,7 @@ class CourseListGetForm(UsernameValidatorMixin, Form): """ Return cleaned data, including additional filters. """ - cleaned_data = super(CourseListGetForm, self).clean() # lint-amnesty, pylint: disable=super-with-arguments + cleaned_data = super().clean() # create a filter for all supported filter fields filter_ = dict() diff --git a/lms/djangoapps/course_api/serializers.py b/lms/djangoapps/course_api/serializers.py index 36117b3cf2..adcf578e74 100644 --- a/lms/djangoapps/course_api/serializers.py +++ b/lms/djangoapps/course_api/serializers.py @@ -3,11 +3,14 @@ Course API Serializers. Representing course catalog data """ -from edx_django_utils import monitoring as monitoring_utils -import six.moves.urllib.parse # lint-amnesty, pylint: disable=wrong-import-order +import urllib + from django.urls import reverse +from edx_django_utils import monitoring as monitoring_utils from rest_framework import serializers +from openedx.core.djangoapps.content.course_overviews.models import \ + CourseOverview # lint-amnesty, pylint: disable=unused-import from openedx.core.djangoapps.models.course_details import CourseDetails from openedx.core.lib.api.fields import AbsoluteURLField @@ -18,7 +21,7 @@ class _MediaSerializer(serializers.Serializer): # pylint: disable=abstract-meth """ def __init__(self, uri_attribute, *args, **kwargs): - super(_MediaSerializer, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) self.uri_attribute = uri_attribute uri = serializers.SerializerMethodField(source='*') @@ -128,7 +131,7 @@ class CourseSerializer(serializers.Serializer): # pylint: disable=abstract-meth """ base_url = '?'.join([ reverse('blocks_in_course'), - six.moves.urllib.parse.urlencode({'course_id': course_overview.id}), + urllib.parse.urlencode({'course_id': course_overview.id}), ]) return self.context['request'].build_absolute_uri(base_url) diff --git a/lms/djangoapps/course_api/tests/mixins.py b/lms/djangoapps/course_api/tests/mixins.py index 349193775b..4ab243ee4f 100644 --- a/lms/djangoapps/course_api/tests/mixins.py +++ b/lms/djangoapps/course_api/tests/mixins.py @@ -8,10 +8,10 @@ from datetime import datetime from common.djangoapps.student.tests.factories import UserFactory from xmodule.modulestore.tests.factories import ToyCourseFactory -TEST_PASSWORD = u'edx' +TEST_PASSWORD = 'edx' -class CourseApiFactoryMixin(object): +class CourseApiFactoryMixin: """ Mixin to allow creation of test courses and users. """ @@ -37,7 +37,7 @@ class CourseApiFactoryMixin(object): """ return UserFactory( username=username, - email=u'{}@example.com'.format(username), + email=f'{username}@example.com', password=TEST_PASSWORD, is_staff=is_staff ) diff --git a/lms/djangoapps/course_api/tests/test_api.py b/lms/djangoapps/course_api/tests/test_api.py index 2b28d4922c..4c01099095 100644 --- a/lms/djangoapps/course_api/tests/test_api.py +++ b/lms/djangoapps/course_api/tests/test_api.py @@ -4,11 +4,11 @@ Test for course API from datetime import datetime, timedelta from hashlib import md5 +from unittest import mock import pytest from django.contrib.auth.models import AnonymousUser from django.http import Http404 -import mock from opaque_keys.edx.keys import CourseKey from rest_framework.exceptions import PermissionDenied from rest_framework.request import Request @@ -30,11 +30,11 @@ class CourseApiTestMixin(CourseApiFactoryMixin): @classmethod def setUpClass(cls): - super(CourseApiTestMixin, cls).setUpClass() + super().setUpClass() cls.request_factory = APIRequestFactory() CourseOverview.get_all_courses() # seed the CourseOverview table - def verify_course(self, course, course_id=u'edX/toy/2012_Fall'): + def verify_course(self, course, course_id='edX/toy/2012_Fall'): """ Ensure that the returned course is the course we just created """ @@ -65,9 +65,9 @@ class TestGetCourseDetail(CourseDetailTestMixin, SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(TestGetCourseDetail, cls).setUpClass() + super().setUpClass() cls.course = cls.create_course() - cls.hidden_course = cls.create_course(course=u'hidden', visible_to_staff_only=True) + cls.hidden_course = cls.create_course(course='hidden', visible_to_staff_only=True) cls.honor_user = cls.create_user('honor', is_staff=False) cls.staff_user = cls.create_user('staff', is_staff=True) @@ -76,7 +76,7 @@ class TestGetCourseDetail(CourseDetailTestMixin, SharedModuleStoreTestCase): self.verify_course(course) def test_get_nonexistent_course(self): - course_key = CourseKey.from_string(u'edX/toy/nope') + course_key = CourseKey.from_string('edX/toy/nope') with pytest.raises(Http404): self._make_api_call(self.honor_user, self.honor_user, course_key) @@ -86,7 +86,7 @@ class TestGetCourseDetail(CourseDetailTestMixin, SharedModuleStoreTestCase): def test_hidden_course_for_staff(self): course = self._make_api_call(self.staff_user, self.staff_user, self.hidden_course.id) - self.verify_course(course, course_id=u'edX/hidden/2012_Fall') + self.verify_course(course, course_id='edX/hidden/2012_Fall') def test_hidden_course_for_staff_as_honor(self): with pytest.raises(Http404): @@ -124,7 +124,7 @@ class TestGetCourseList(CourseListTestMixin, SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(TestGetCourseList, cls).setUpClass() + super().setUpClass() cls.course = cls.create_course() cls.staff_user = cls.create_user("staff", is_staff=True) cls.honor_user = cls.create_user("honor", is_staff=False) @@ -165,7 +165,7 @@ class TestGetCourseListMultipleCourses(CourseListTestMixin, ModuleStoreTestCase) ENABLED_SIGNALS = ['course_published'] def setUp(self): - super(TestGetCourseListMultipleCourses, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = self.create_course(mobile_available=False) self.staff_user = self.create_user("staff", is_staff=True) self.honor_user = self.create_user("honor", is_staff=False) @@ -217,7 +217,7 @@ class TestGetCourseListExtras(CourseListTestMixin, ModuleStoreTestCase): @classmethod def setUpClass(cls): - super(TestGetCourseListExtras, cls).setUpClass() + super().setUpClass() cls.staff_user = cls.create_user("staff", is_staff=True) cls.honor_user = cls.create_user("honor", is_staff=False) diff --git a/lms/djangoapps/course_api/tests/test_forms.py b/lms/djangoapps/course_api/tests/test_forms.py index 2fce9e2805..8eda36e97c 100644 --- a/lms/djangoapps/course_api/tests/test_forms.py +++ b/lms/djangoapps/course_api/tests/test_forms.py @@ -3,22 +3,21 @@ Tests for Course API forms. """ from itertools import product +from urllib.parse import urlencode import ddt -import six -from six.moves.urllib.parse import urlencode from django.contrib.auth.models import AnonymousUser from django.http import QueryDict -from openedx.core.djangoapps.util.test_forms import FormTestMixin from common.djangoapps.student.tests.factories import UserFactory +from openedx.core.djangoapps.util.test_forms import FormTestMixin from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory from ..forms import CourseDetailGetForm, CourseIdListGetForm, CourseListGetForm -class UsernameTestMixin(object): +class UsernameTestMixin: """ Tests the username Form field. """ @@ -43,12 +42,12 @@ class TestCourseListGetForm(FormTestMixin, UsernameTestMixin, SharedModuleStoreT @classmethod def setUpClass(cls): - super(TestCourseListGetForm, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() def setUp(self): - super(TestCourseListGetForm, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.student = UserFactory.create() self.set_up_data(self.student) @@ -105,12 +104,12 @@ class TestCourseIdListGetForm(FormTestMixin, UsernameTestMixin, SharedModuleStor @classmethod def setUpClass(cls): - super(TestCourseIdListGetForm, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() def setUp(self): - super(TestCourseIdListGetForm, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.student = UserFactory.create() self.set_up_data(self.student) @@ -144,12 +143,12 @@ class TestCourseDetailGetForm(FormTestMixin, UsernameTestMixin, SharedModuleStor @classmethod def setUpClass(cls): - super(TestCourseDetailGetForm, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() def setUp(self): - super(TestCourseDetailGetForm, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.student = UserFactory.create() self.set_up_data(self.student) @@ -162,7 +161,7 @@ class TestCourseDetailGetForm(FormTestMixin, UsernameTestMixin, SharedModuleStor self.form_data = QueryDict( urlencode({ 'username': user.username, - 'course_key': six.text_type(self.course.id), + 'course_key': str(self.course.id), }), mutable=True, ) diff --git a/lms/djangoapps/course_api/tests/test_permissions.py b/lms/djangoapps/course_api/tests/test_permissions.py index b7644103f9..ef0cf3240f 100644 --- a/lms/djangoapps/course_api/tests/test_permissions.py +++ b/lms/djangoapps/course_api/tests/test_permissions.py @@ -20,7 +20,7 @@ class ViewCoursesForUsernameTestCase(CourseApiFactoryMixin, TestCase): @classmethod def setUpClass(cls): - super(ViewCoursesForUsernameTestCase, cls).setUpClass() + super().setUpClass() cls.staff_user = cls.create_user('staff', is_staff=True) cls.honor_user = cls.create_user('honor', is_staff=False) cls.anonymous_user = AnonymousUser() diff --git a/lms/djangoapps/course_api/tests/test_serializers.py b/lms/djangoapps/course_api/tests/test_serializers.py index 5d0453e989..834c975218 100644 --- a/lms/djangoapps/course_api/tests/test_serializers.py +++ b/lms/djangoapps/course_api/tests/test_serializers.py @@ -7,10 +7,10 @@ from datetime import datetime from unittest import TestCase import ddt +from opaque_keys.edx.locator import CourseLocator from rest_framework.request import Request from rest_framework.test import APIRequestFactory from xblock.core import XBlock -from opaque_keys.edx.locator import CourseLocator from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.models.course_details import CourseDetails @@ -34,22 +34,22 @@ class TestCourseSerializer(CourseApiFactoryMixin, ModuleStoreTestCase): ENABLED_SIGNALS = ['course_published'] def setUp(self): - super(TestCourseSerializer, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.staff_user = self.create_user('staff', is_staff=True) self.honor_user = self.create_user('honor', is_staff=False) self.request_factory = APIRequestFactory() - course_id = u'edX/toy/2012_Fall' - banner_image_uri = u'/c4x/edX/toy/asset/images_course_image.jpg' - banner_image_absolute_uri = u'http://testserver' + banner_image_uri - image_path = u'/c4x/edX/toy/asset/just_a_test.jpg' - image_url = u'http://testserver' + image_path + course_id = 'edX/toy/2012_Fall' + banner_image_uri = '/c4x/edX/toy/asset/images_course_image.jpg' + banner_image_absolute_uri = 'http://testserver' + banner_image_uri + image_path = '/c4x/edX/toy/asset/just_a_test.jpg' + image_url = 'http://testserver' + image_path self.expected_data = { 'id': course_id, - 'name': u'Toy Course', - 'number': u'toy', - 'org': u'edX', - 'short_description': u'A course about toys.', + 'name': 'Toy Course', + 'number': 'toy', + 'org': 'edX', + 'short_description': 'A course about toys.', 'media': { 'banner_image': { 'uri': banner_image_uri, @@ -59,7 +59,7 @@ class TestCourseSerializer(CourseApiFactoryMixin, ModuleStoreTestCase): 'uri': image_path, }, 'course_video': { - 'uri': u'http://www.youtube.com/watch?v=test_youtube_id', + 'uri': 'http://www.youtube.com/watch?v=test_youtube_id', }, 'image': { 'raw': image_url, @@ -67,14 +67,14 @@ class TestCourseSerializer(CourseApiFactoryMixin, ModuleStoreTestCase): 'large': image_url, } }, - 'start': u'2015-07-17T12:00:00Z', - 'start_type': u'timestamp', - 'start_display': u'July 17, 2015', - 'end': u'2015-09-19T18:00:00Z', - 'enrollment_start': u'2015-06-15T00:00:00Z', - 'enrollment_end': u'2015-07-15T00:00:00Z', - 'blocks_url': u'http://testserver/api/courses/v2/blocks/?course_id=edX%2Ftoy%2F2012_Fall', - 'effort': u'6 hours', + 'start': '2015-07-17T12:00:00Z', + 'start_type': 'timestamp', + 'start_display': 'July 17, 2015', + 'end': '2015-09-19T18:00:00Z', + 'enrollment_start': '2015-06-15T00:00:00Z', + 'enrollment_end': '2015-07-15T00:00:00Z', + 'blocks_url': 'http://testserver/api/courses/v2/blocks/?course_id=edX%2Ftoy%2F2012_Fall', + 'effort': '6 hours', 'pacing': 'instructor', 'mobile_available': True, 'hidden': False, @@ -110,29 +110,29 @@ class TestCourseSerializer(CourseApiFactoryMixin, ModuleStoreTestCase): def test_hidden(self): course = self.create_course( - course=u'custom', + course='custom', start=datetime(2015, 3, 15), - catalog_visibility=u'none' + catalog_visibility='none' ) result = self._get_result(course) assert result['hidden'] is True def test_advertised_start(self): course = self.create_course( - course=u'custom', + course='custom', start=datetime(2015, 3, 15), - advertised_start=u'The Ides of March' + advertised_start='The Ides of March' ) result = self._get_result(course) - assert result['course_id'] == u'edX/custom/2012_Fall' - assert result['start_type'] == u'string' - assert result['start_display'] == u'The Ides of March' + assert result['course_id'] == 'edX/custom/2012_Fall' + assert result['start_type'] == 'string' + assert result['start_display'] == 'The Ides of March' def test_empty_start(self): - course = self.create_course(start=DEFAULT_START_DATE, course=u'custom') + course = self.create_course(start=DEFAULT_START_DATE, course='custom') result = self._get_result(course) - assert result['course_id'] == u'edX/custom/2012_Fall' - assert result['start_type'] == u'empty' + assert result['course_id'] == 'edX/custom/2012_Fall' + assert result['start_type'] == 'empty' assert result['start_display'] is None @ddt.unpack @@ -158,7 +158,7 @@ class TestCourseDetailSerializer(TestCourseSerializer): # lint-amnesty, pylint: serializer_class = CourseDetailSerializer def setUp(self): - super(TestCourseDetailSerializer, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # update the expected_data to include the 'overview' data. about_descriptor = XBlock.load_class('about') diff --git a/lms/djangoapps/course_api/tests/test_views.py b/lms/djangoapps/course_api/tests/test_views.py index 87c7e233ec..6b8a1a7737 100644 --- a/lms/djangoapps/course_api/tests/test_views.py +++ b/lms/djangoapps/course_api/tests/test_views.py @@ -7,13 +7,12 @@ from hashlib import md5 from unittest import TestCase import pytest import ddt -import six -from six.moves import range from django.core.exceptions import ImproperlyConfigured from django.test import RequestFactory from django.test.utils import override_settings from django.urls import reverse from edx_django_utils.cache import RequestCache +from opaque_keys.edx.locator import LibraryLocator from search.tests.test_course_discovery import DemoCourse from search.tests.tests import TEST_INDEX_NAME from search.tests.utils import SearcherMixin @@ -21,13 +20,12 @@ from waffle.testutils import override_switch from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.course_modes.tests.factories import CourseModeFactory -from opaque_keys.edx.locator import LibraryLocator # lint-amnesty, pylint: disable=wrong-import-order -from openedx.core.lib.api.view_utils import LazySequence -from openedx.features.content_type_gating.models import ContentTypeGatingConfig -from openedx.features.course_duration_limits.models import CourseDurationLimitConfig from common.djangoapps.student.auth import add_users from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole from common.djangoapps.student.tests.factories import AdminFactory +from openedx.core.lib.api.view_utils import LazySequence +from openedx.features.content_type_gating.models import ContentTypeGatingConfig +from openedx.features.course_duration_limits.models import CourseDurationLimitConfig from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -78,7 +76,7 @@ class CourseListViewTestCase(CourseApiTestViewMixin, SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(CourseListViewTestCase, cls).setUpClass() + super().setUpClass() cls.course = cls.create_course() cls.url = reverse('course-list') cls.staff_user = cls.create_user(username='staff', is_staff=True) @@ -159,7 +157,7 @@ class CourseListViewTestCaseMultipleCourses(CourseApiTestViewMixin, ModuleStoreT ENABLED_SIGNALS = ['course_published'] def setUp(self): - super(CourseListViewTestCaseMultipleCourses, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = self.create_course(mobile_available=False) self.url = reverse('course-list') self.staff_user = self.create_user(username='staff', is_staff=True) @@ -201,7 +199,7 @@ class CourseListViewTestCaseMultipleCourses(CourseApiTestViewMixin, ModuleStoreT if filter_: params.update(filter_) response = self.verify_response(params=params) - assert {course['course_id'] for course in response.data['results']} == {six.text_type(course.id) for course in expected_courses}, f'testing course_api.views.CourseListView with filter_={filter_}' # pylint: disable=line-too-long + assert {course['course_id'] for course in response.data['results']} == {str(course.id) for course in expected_courses}, f'testing course_api.views.CourseListView with filter_={filter_}' # pylint: disable=line-too-long class CourseDetailViewTestCase(CourseApiTestViewMixin, SharedModuleStoreTestCase): @@ -211,9 +209,9 @@ class CourseDetailViewTestCase(CourseApiTestViewMixin, SharedModuleStoreTestCase @classmethod def setUpClass(cls): - super(CourseDetailViewTestCase, cls).setUpClass() + super().setUpClass() cls.course = cls.create_course() - cls.hidden_course = cls.create_course(course=u'hidden', visible_to_staff_only=True) + cls.hidden_course = cls.create_course(course='hidden', visible_to_staff_only=True) cls.url = reverse('course-detail', kwargs={'course_key_string': cls.course.id}) cls.hidden_url = reverse('course-detail', kwargs={'course_key_string': cls.hidden_course.id}) cls.nonexistent_url = reverse('course-detail', kwargs={'course_key_string': 'edX/nope/Fall_2014'}) @@ -289,7 +287,7 @@ class CourseListSearchViewTest(CourseApiTestViewMixin, ModuleStoreTestCase, Sear ENABLED_CACHES = ModuleStoreTestCase.ENABLED_CACHES + ['configuration'] def setUp(self): - super(CourseListSearchViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() DemoCourse.reset_count() self.searcher.destroy() @@ -316,7 +314,7 @@ class CourseListSearchViewTest(CourseApiTestViewMixin, ModuleStoreTestCase, Sear 'run': '2010', 'number': 'DemoZ', # Using the slash separated course ID bcuz `DemoCourse` isn't updated yet to new locator. - 'id': '{org_code}/DemoZ/2010'.format(org_code=org_code), + 'id': f'{org_code}/DemoZ/2010', 'content': { 'short_description': short_description, }, @@ -377,10 +375,10 @@ class CourseListSearchViewTest(CourseApiTestViewMixin, ModuleStoreTestCase, Sear # Create 300 courses across 30 organizations for org_num in range(10): - org_id = 'org{}'.format(org_num) + org_id = f'org{org_num}' for course_num in range(30): - course_name = 'course{}.{}'.format(org_num, course_num) - course_run_name = 'run{}.{}'.format(org_num, course_num) + course_name = f'course{org_num}.{course_num}' + course_run_name = f'run{org_num}.{course_num}' course = CourseFactory.create(org=org_id, number=course_name, run=course_run_name, emit_signals=True) CourseModeFactory.create(course_id=course.id, mode_slug=CourseMode.AUDIT) CourseModeFactory.create(course_id=course.id, mode_slug=CourseMode.VERIFIED) @@ -412,7 +410,7 @@ class CourseIdListViewTestCase(CourseApiTestViewMixin, ModuleStoreTestCase): ENABLED_SIGNALS = ['course_published'] def setUp(self): - super(CourseIdListViewTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = self.create_course() self.url = reverse('course-id-list') self.staff_user = self.create_user(username='staff', is_staff=True) @@ -528,7 +526,7 @@ class CourseIdListViewTestCase(CourseApiTestViewMixin, ModuleStoreTestCase): class LazyPageNumberPaginationTestCase(TestCase): # lint-amnesty, pylint: disable=missing-class-docstring def test_lazy_page_number_pagination(self): - number_sequence = range(20) + number_sequence = range(20) # lint-amnesty, pylint: disable=range-builtin-not-iterating even_numbers_lazy_sequence = LazySequence( ( number for number in number_sequence @@ -557,7 +555,7 @@ class LazyPageNumberPaginationTestCase(TestCase): # lint-amnesty, pylint: disab self.assertDictEqual(expected_response, paginated_response.data) def test_not_found_error_for_invalid_page(self): - number_sequence = range(20) + number_sequence = range(20) # lint-amnesty, pylint: disable=range-builtin-not-iterating even_numbers_lazy_sequence = LazySequence( ( number for number in number_sequence diff --git a/lms/djangoapps/course_api/urls.py b/lms/djangoapps/course_api/urls.py index ba688b7f04..d030f5b8e0 100644 --- a/lms/djangoapps/course_api/urls.py +++ b/lms/djangoapps/course_api/urls.py @@ -10,7 +10,7 @@ from .views import CourseDetailView, CourseIdListView, CourseListView urlpatterns = [ url(r'^v1/courses/$', CourseListView.as_view(), name="course-list"), - url(r'^v1/courses/{}'.format(settings.COURSE_KEY_PATTERN), CourseDetailView.as_view(), name="course-detail"), + url(fr'^v1/courses/{settings.COURSE_KEY_PATTERN}', CourseDetailView.as_view(), name="course-detail"), url(r'^v1/course_ids/$', CourseIdListView.as_view(), name="course-id-list"), url(r'', include('lms.djangoapps.course_api.blocks.urls')) ] diff --git a/lms/djangoapps/course_api/views.py b/lms/djangoapps/course_api/views.py index 03fe46355f..a1e5ef845e 100644 --- a/lms/djangoapps/course_api/views.py +++ b/lms/djangoapps/course_api/views.py @@ -7,9 +7,9 @@ from django.core.exceptions import ValidationError from django.core.paginator import InvalidPage from edx_django_utils.monitoring import function_trace from edx_rest_framework_extensions.paginators import NamespacedPageNumberPagination +from rest_framework.exceptions import NotFound from rest_framework.generics import ListAPIView, RetrieveAPIView from rest_framework.throttling import UserRateThrottle -from rest_framework.exceptions import NotFound from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin, view_auth_classes @@ -159,7 +159,7 @@ class CourseListUserThrottle(UserRateThrottle): self.rate = self.get_rate() self.num_requests, self.duration = self.parse_rate(self.rate) - return super(CourseListUserThrottle, self).allow_request(request, view) # lint-amnesty, pylint: disable=super-with-arguments + return super().allow_request(request, view) class LazyPageNumberPagination(NamespacedPageNumberPagination): @@ -193,7 +193,7 @@ class LazyPageNumberPagination(NamespacedPageNumberPagination): self.page.number = self.page.paginator.num_pages raise NotFound(msg) # lint-amnesty, pylint: disable=raise-missing-from - return super(LazyPageNumberPagination, self).get_paginated_response(data) # lint-amnesty, pylint: disable=super-with-arguments + return super().get_paginated_response(data) @function_trace('pagination_paginate_queryset') def paginate_queryset(self, queryset, request, view=None): @@ -347,7 +347,7 @@ class CourseIdListUserThrottle(UserRateThrottle): self.rate = self.get_rate() self.num_requests, self.duration = self.parse_rate(self.rate) - return super(CourseIdListUserThrottle, self).allow_request(request, view) # lint-amnesty, pylint: disable=super-with-arguments + return super().allow_request(request, view) @view_auth_classes() @@ -434,7 +434,7 @@ class CourseIdListView(DeveloperErrorViewMixin, ListAPIView): This should be called once per GET request. """ - return super(CourseIdListView, self).paginate_queryset(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + return super().paginate_queryset(*args, **kwargs) @function_trace('get_paginated_response') def get_paginated_response(self, *args, **kwargs): @@ -446,7 +446,7 @@ class CourseIdListView(DeveloperErrorViewMixin, ListAPIView): means two GET requests and one function call per request. Otherwise, if the whole response fits in one page, this function never gets called. """ - return super(CourseIdListView, self).get_paginated_response(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + return super().get_paginated_response(*args, **kwargs) @function_trace('filter_queryset') def filter_queryset(self, *args, **kwargs): @@ -456,7 +456,7 @@ class CourseIdListView(DeveloperErrorViewMixin, ListAPIView): This should be called once per GET request. """ - return super(CourseIdListView, self).filter_queryset(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + return super().filter_queryset(*args, **kwargs) @function_trace('get_serializer') def get_serializer(self, *args, **kwargs): @@ -466,4 +466,4 @@ class CourseIdListView(DeveloperErrorViewMixin, ListAPIView): This should be called once per GET request. """ - return super(CourseIdListView, self).get_serializer(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + return super().get_serializer(*args, **kwargs)