diff --git a/openedx/core/djangoapps/enrollments/api.py b/openedx/core/djangoapps/enrollments/api.py index 4dcc02cbaf..d2e39982c4 100644 --- a/openedx/core/djangoapps/enrollments/api.py +++ b/openedx/core/djangoapps/enrollments/api.py @@ -257,7 +257,7 @@ def update_enrollment( } """ - log.info(u'Starting Update Enrollment process for user {user} in course {course} to mode {mode}'.format( + log.info('Starting Update Enrollment process for user {user} in course {course} to mode {mode}'.format( user=username, course=course_id, mode=mode, @@ -266,13 +266,13 @@ def update_enrollment( validate_course_mode(course_id, mode, is_active=is_active, include_expired=include_expired) enrollment = _data_api().update_course_enrollment(username, course_id, mode=mode, is_active=is_active) if enrollment is None: # lint-amnesty, pylint: disable=no-else-raise - msg = u"Course Enrollment not found for user {user} in course {course}".format(user=username, course=course_id) + msg = f"Course Enrollment not found for user {username} in course {course_id}" log.warning(msg) raise errors.EnrollmentNotFoundError(msg) else: if enrollment_attributes is not None: set_enrollment_attributes(username, course_id, enrollment_attributes) - log.info(u'Course Enrollment updated for user {user} in course {course} to mode {mode}'.format( + log.info('Course Enrollment updated for user {user} in course {course} to mode {mode}'.format( user=username, course=course_id, mode=mode @@ -320,16 +320,13 @@ def get_course_enrollment_details(course_id, include_expired=False): } """ - cache_key = u'enrollment.course.details.{course_id}.{include_expired}'.format( - course_id=course_id, - include_expired=include_expired - ) + cache_key = f'enrollment.course.details.{course_id}.{include_expired}' cached_enrollment_data = None try: cached_enrollment_data = cache.get(cache_key) except Exception: # pylint: disable=broad-except # The cache backend could raise an exception (for example, memcache keys that contain spaces) - log.exception(u"Error occurred while retrieving course enrollment details from the cache") + log.exception("Error occurred while retrieving course enrollment details from the cache") if cached_enrollment_data: return cached_enrollment_data @@ -341,8 +338,8 @@ def get_course_enrollment_details(course_id, include_expired=False): cache.set(cache_key, course_enrollment_details, cache_time_out) except Exception: # Catch any unexpected errors during caching. - log.exception(u"Error occurred while caching course enrollment details for course %s", course_id) - raise errors.CourseEnrollmentError(u"An unexpected error occurred while retrieving course enrollment details.") # lint-amnesty, pylint: disable=raise-missing-from + log.exception("Error occurred while caching course enrollment details for course %s", course_id) + raise errors.CourseEnrollmentError("An unexpected error occurred while retrieving course enrollment details.") # lint-amnesty, pylint: disable=raise-missing-from return course_enrollment_details @@ -449,8 +446,8 @@ def validate_course_mode(course_id, mode, is_active=None, include_expired=False) available_modes = [m['slug'] for m in course_modes] if mode not in available_modes: msg = ( - u"Specified course mode '{mode}' unavailable for course {course_id}. " - u"Available modes were: {available}" + "Specified course mode '{mode}' unavailable for course {course_id}. " + "Available modes were: {available}" ).format( mode=mode, course_id=course_id, @@ -550,5 +547,5 @@ def _data_api(): try: return importlib.import_module(api_path) except (ImportError, ValueError): - log.exception(u"Could not load module at '{path}'".format(path=api_path)) + log.exception(f"Could not load module at '{api_path}'") raise errors.EnrollmentApiLoadError(api_path) # lint-amnesty, pylint: disable=raise-missing-from diff --git a/openedx/core/djangoapps/enrollments/apps.py b/openedx/core/djangoapps/enrollments/apps.py index 961c41067e..b2d3d4fc0f 100644 --- a/openedx/core/djangoapps/enrollments/apps.py +++ b/openedx/core/djangoapps/enrollments/apps.py @@ -1,4 +1,3 @@ - """ Enrollments Application Configuration @@ -15,7 +14,7 @@ class EnrollmentsConfig(AppConfig): """ Application Configuration for Enrollments. """ - name = u'openedx.core.djangoapps.enrollments' + name = 'openedx.core.djangoapps.enrollments' def ready(self): """ diff --git a/openedx/core/djangoapps/enrollments/data.py b/openedx/core/djangoapps/enrollments/data.py index f6edce9533..457a03bdcb 100644 --- a/openedx/core/djangoapps/enrollments/data.py +++ b/openedx/core/djangoapps/enrollments/data.py @@ -9,7 +9,6 @@ import logging from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user from django.db import transaction from opaque_keys.edx.keys import CourseKey -from six import text_type from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.enrollments.errors import ( @@ -69,8 +68,8 @@ def get_course_enrollments(username, include_inactive=False): if deleted: log.warning( ( - u"Course enrollments for user %s reference " - u"courses that do not exist (this can occur if a course is deleted)." + "Course enrollments for user %s reference " + "courses that do not exist (this can occur if a course is deleted)." ), username, ) @@ -142,7 +141,7 @@ def create_course_enrollment(username, course_id, mode, is_active): try: user = User.objects.get(username=username) except User.DoesNotExist: - msg = u"Not user with username '{username}' found.".format(username=username) + msg = f"Not user with username '{username}' found." log.warning(msg) raise UserNotFoundError(msg) # lint-amnesty, pylint: disable=raise-missing-from @@ -150,14 +149,14 @@ def create_course_enrollment(username, course_id, mode, is_active): enrollment = CourseEnrollment.enroll(user, course_key, check_access=True) return _update_enrollment(enrollment, is_active=is_active, mode=mode) except NonExistentCourseError as err: - raise CourseNotFoundError(text_type(err)) # lint-amnesty, pylint: disable=raise-missing-from + raise CourseNotFoundError(str(err)) # lint-amnesty, pylint: disable=raise-missing-from except EnrollmentClosedError as err: - raise CourseEnrollmentClosedError(text_type(err)) # lint-amnesty, pylint: disable=raise-missing-from + raise CourseEnrollmentClosedError(str(err)) # lint-amnesty, pylint: disable=raise-missing-from except CourseFullError as err: - raise CourseEnrollmentFullError(text_type(err)) # lint-amnesty, pylint: disable=raise-missing-from + raise CourseEnrollmentFullError(str(err)) # lint-amnesty, pylint: disable=raise-missing-from except AlreadyEnrolledError as err: enrollment = get_course_enrollment(username, course_id) - raise CourseEnrollmentExistsError(text_type(err), enrollment) # lint-amnesty, pylint: disable=raise-missing-from + raise CourseEnrollmentExistsError(str(err), enrollment) # lint-amnesty, pylint: disable=raise-missing-from def update_course_enrollment(username, course_id, mode=None, is_active=None): @@ -180,7 +179,7 @@ def update_course_enrollment(username, course_id, mode=None, is_active=None): try: user = User.objects.get(username=username) except User.DoesNotExist: - msg = u"Not user with username '{username}' found.".format(username=username) + msg = f"Not user with username '{username}' found." log.warning(msg) raise UserNotFoundError(msg) # lint-amnesty, pylint: disable=raise-missing-from @@ -257,7 +256,7 @@ def unenroll_user_from_all_courses(username): for enrollment in enrollments: _update_enrollment(enrollment, is_active=False) - return set([str(enrollment.course_id.org) for enrollment in enrollments]) # lint-amnesty, pylint: disable=consider-using-set-comprehension + return {str(enrollment.course_id.org) for enrollment in enrollments} # lint-amnesty, pylint: disable=consider-using-set-comprehension def _get_user(username): @@ -271,7 +270,7 @@ def _get_user(username): try: return User.objects.get(username=username) except User.DoesNotExist: - msg = u"Not user with username '{username}' found.".format(username=username) + msg = f"Not user with username '{username}' found." log.warning(msg) raise UserNotFoundError(msg) # lint-amnesty, pylint: disable=raise-missing-from @@ -294,17 +293,17 @@ def _invalid_attribute(attributes): invalid_attributes = [] for attribute in attributes: if "namespace" not in attribute: - msg = u"'namespace' not in enrollment attribute" + msg = "'namespace' not in enrollment attribute" log.warning(msg) invalid_attributes.append("namespace") raise InvalidEnrollmentAttribute(msg) if "name" not in attribute: - msg = u"'name' not in enrollment attribute" + msg = "'name' not in enrollment attribute" log.warning(msg) invalid_attributes.append("name") raise InvalidEnrollmentAttribute(msg) if "value" not in attribute: - msg = u"'value' not in enrollment attribute" + msg = "'value' not in enrollment attribute" log.warning(msg) invalid_attributes.append("value") raise InvalidEnrollmentAttribute(msg) @@ -335,7 +334,7 @@ def get_course_enrollment_info(course_id, include_expired=False): try: course = CourseOverview.get_from_id(course_key) except CourseOverview.DoesNotExist: - msg = u"Requested enrollment information for unknown course {course}".format(course=course_id) + msg = f"Requested enrollment information for unknown course {course_id}" log.warning(msg) raise CourseNotFoundError(msg) # lint-amnesty, pylint: disable=raise-missing-from else: diff --git a/openedx/core/djangoapps/enrollments/errors.py b/openedx/core/djangoapps/enrollments/errors.py index 45ca983b56..d75ec94352 100644 --- a/openedx/core/djangoapps/enrollments/errors.py +++ b/openedx/core/djangoapps/enrollments/errors.py @@ -8,7 +8,7 @@ class CourseEnrollmentError(Exception): """ def __init__(self, msg, data=None): - super(CourseEnrollmentError, self).__init__(msg) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(msg) # Corresponding information to help resolve the error. self.data = data @@ -29,7 +29,7 @@ class CourseEnrollmentExistsError(CourseEnrollmentError): # lint-amnesty, pylin enrollment = None def __init__(self, message, enrollment): - super(CourseEnrollmentExistsError, self).__init__(message) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(message) self.enrollment = enrollment diff --git a/openedx/core/djangoapps/enrollments/forms.py b/openedx/core/djangoapps/enrollments/forms.py index 30dd497179..5285792890 100644 --- a/openedx/core/djangoapps/enrollments/forms.py +++ b/openedx/core/djangoapps/enrollments/forms.py @@ -28,7 +28,7 @@ class CourseEnrollmentsApiListForm(Form): try: return CourseKey.from_string(course_id) except InvalidKeyError: - raise ValidationError(u"'{}' is not a valid course id.".format(course_id)) # lint-amnesty, pylint: disable=raise-missing-from + raise ValidationError(f"'{course_id}' is not a valid course id.") # lint-amnesty, pylint: disable=raise-missing-from return course_id def clean_username(self): @@ -40,7 +40,7 @@ class CourseEnrollmentsApiListForm(Form): usernames = usernames_csv_string.split(',') if len(usernames) > self.MAX_USERNAME_COUNT: raise ValidationError( - u"Too many usernames in a single request - {}. A maximum of {} is allowed".format( + "Too many usernames in a single request - {}. A maximum of {} is allowed".format( len(usernames), self.MAX_USERNAME_COUNT, ) diff --git a/openedx/core/djangoapps/enrollments/management/tests/test_enroll_user_in_course.py b/openedx/core/djangoapps/enrollments/management/tests/test_enroll_user_in_course.py index c9dd40e428..b91242469a 100644 --- a/openedx/core/djangoapps/enrollments/management/tests/test_enroll_user_in_course.py +++ b/openedx/core/djangoapps/enrollments/management/tests/test_enroll_user_in_course.py @@ -14,8 +14,6 @@ from common.djangoapps.student.tests.factories import UserFactory from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory -import six # lint-amnesty, pylint: disable=wrong-import-order -from six.moves import range # lint-amnesty, pylint: disable=wrong-import-order @ddt.ddt @@ -27,12 +25,12 @@ class EnrollManagementCommandTest(SharedModuleStoreTestCase): @classmethod def setUpClass(cls): - super(EnrollManagementCommandTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create(org='fooX', number='007') def setUp(self): - super(EnrollManagementCommandTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments - self.course_id = six.text_type(self.course.id) + super().setUp() + self.course_id = str(self.course.id) self.username = 'ralph' + uuid4().hex self.user_email = self.username + '@example.com' diff --git a/openedx/core/djangoapps/enrollments/serializers.py b/openedx/core/djangoapps/enrollments/serializers.py index 2816d0f52e..db93b6bb9c 100644 --- a/openedx/core/djangoapps/enrollments/serializers.py +++ b/openedx/core/djangoapps/enrollments/serializers.py @@ -45,13 +45,13 @@ class CourseSerializer(serializers.Serializer): # pylint: disable=abstract-meth invite_only = serializers.BooleanField(source="invitation_only") course_modes = serializers.SerializerMethodField() - class Meta(object): + class Meta: # For disambiguating within the drf-yasg swagger schema ref_name = 'enrollment.Course' def __init__(self, *args, **kwargs): self.include_expired = kwargs.pop("include_expired", False) - super(CourseSerializer, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) def get_course_modes(self, obj): """ @@ -82,7 +82,7 @@ class CourseEnrollmentSerializer(serializers.ModelSerializer): """Retrieves the username from the associated model.""" return model.username - class Meta(object): + class Meta: model = CourseEnrollment fields = ('created', 'mode', 'is_active', 'course_details', 'user') lookup_field = 'username' @@ -96,7 +96,7 @@ class CourseEnrollmentsApiListSerializer(CourseEnrollmentSerializer): course_id = serializers.CharField(source='course_overview.id') def __init__(self, *args, **kwargs): - super(CourseEnrollmentsApiListSerializer, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) self.fields.pop('course_details') class Meta(CourseEnrollmentSerializer.Meta): diff --git a/openedx/core/djangoapps/enrollments/services.py b/openedx/core/djangoapps/enrollments/services.py index 8b81db3c1c..c10a5187ec 100644 --- a/openedx/core/djangoapps/enrollments/services.py +++ b/openedx/core/djangoapps/enrollments/services.py @@ -13,7 +13,7 @@ from common.djangoapps.student.models import CourseEnrollment from xmodule.modulestore.django import modulestore -class EnrollmentsService(object): +class EnrollmentsService: """ Enrollments service diff --git a/openedx/core/djangoapps/enrollments/tests/test_api.py b/openedx/core/djangoapps/enrollments/tests/test_api.py index 89bfbbc17a..e3a95df6fd 100644 --- a/openedx/core/djangoapps/enrollments/tests/test_api.py +++ b/openedx/core/djangoapps/enrollments/tests/test_api.py @@ -4,12 +4,12 @@ Tests for student enrollment. import unittest +from unittest.mock import Mock, patch import ddt import pytest from django.conf import settings from django.test.utils import override_settings -from mock import Mock, patch from common.djangoapps.course_modes.models import CourseMode from openedx.core.djangoapps.enrollments import api @@ -33,7 +33,7 @@ class EnrollmentTest(CacheIsolationTestCase): ENABLED_CACHES = ['default'] def setUp(self): - super(EnrollmentTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() fake_data_api.reset() @ddt.data( diff --git a/openedx/core/djangoapps/enrollments/tests/test_data.py b/openedx/core/djangoapps/enrollments/tests/test_data.py index f4e2b2a513..918d5c08cf 100644 --- a/openedx/core/djangoapps/enrollments/tests/test_data.py +++ b/openedx/core/djangoapps/enrollments/tests/test_data.py @@ -6,14 +6,12 @@ Test the Data Aggregation Layer for Course Enrollments. import datetime import unittest +from unittest.mock import patch import ddt import pytest -import six from django.conf import settings -from mock import patch from pytz import UTC -from six.moves import range from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.course_modes.tests.factories import CourseModeFactory @@ -45,7 +43,7 @@ class EnrollmentDataTest(ModuleStoreTestCase): def setUp(self): """Create a course and user, then log in. """ - super(EnrollmentDataTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create() self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD) self.client.login(username=self.USERNAME, password=self.PASSWORD) @@ -66,7 +64,7 @@ class EnrollmentDataTest(ModuleStoreTestCase): self._create_course_modes(course_modes) enrollment = data.create_course_enrollment( self.user.username, - six.text_type(self.course.id), + str(self.course.id), enrollment_mode, True ) @@ -87,7 +85,7 @@ class EnrollmentDataTest(ModuleStoreTestCase): enrollment = data.update_course_enrollment( self.user.username, - six.text_type(self.course.id), + str(self.course.id), is_active=False ) @@ -106,7 +104,7 @@ class EnrollmentDataTest(ModuleStoreTestCase): ) def test_get_course_info(self, course_modes): self._create_course_modes(course_modes, course=self.course) - result_course = data.get_course_enrollment_info(six.text_type(self.course.id)) + result_course = data.get_course_enrollment_info(str(self.course.id)) result_slugs = [mode['slug'] for mode in result_course['course_modes']] for course_mode in course_modes: assert course_mode in result_slugs @@ -131,7 +129,7 @@ class EnrollmentDataTest(ModuleStoreTestCase): # Create the original enrollment. created_enrollments.append(data.create_course_enrollment( self.user.username, - six.text_type(course.id), + str(course.id), 'honor', True )) @@ -172,7 +170,7 @@ class EnrollmentDataTest(ModuleStoreTestCase): # Create the original enrollment. created_enrollments.append(data.create_course_enrollment( self.user.username, - six.text_type(course.id), + str(course.id), 'honor', True )) @@ -180,7 +178,7 @@ class EnrollmentDataTest(ModuleStoreTestCase): # deactivate one enrollment data.update_course_enrollment( self.user.username, - six.text_type(created_courses[0].id), + str(created_courses[0].id), 'honor', False ) @@ -208,18 +206,18 @@ class EnrollmentDataTest(ModuleStoreTestCase): self._create_course_modes(course_modes) # Try to get an enrollment before it exists. - result = data.get_course_enrollment(self.user.username, six.text_type(self.course.id)) + result = data.get_course_enrollment(self.user.username, str(self.course.id)) assert result is None # Create the original enrollment. enrollment = data.create_course_enrollment( self.user.username, - six.text_type(self.course.id), + str(self.course.id), enrollment_mode, True ) # Get the enrollment and compare it to the original. - result = data.get_course_enrollment(self.user.username, six.text_type(self.course.id)) + result = data.get_course_enrollment(self.user.username, str(self.course.id)) assert self.user.username == result['user'] assert enrollment == result @@ -255,7 +253,7 @@ class EnrollmentDataTest(ModuleStoreTestCase): for user in users: created_enrollments.append(data.create_course_enrollment( user.username, - six.text_type(self.course.id), + str(self.course.id), enrollment_mode, True )) @@ -282,7 +280,7 @@ class EnrollmentDataTest(ModuleStoreTestCase): def test_add_or_update_enrollment_attr(self, course_modes, enrollment_mode): # Create the course modes (if any) required for this test case self._create_course_modes(course_modes) - data.create_course_enrollment(self.user.username, six.text_type(self.course.id), enrollment_mode, True) + data.create_course_enrollment(self.user.username, str(self.course.id), enrollment_mode, True) enrollment_attributes = [ { "namespace": "credit", @@ -291,8 +289,8 @@ class EnrollmentDataTest(ModuleStoreTestCase): } ] - data.add_or_update_enrollment_attr(self.user.username, six.text_type(self.course.id), enrollment_attributes) - enrollment_attr = data.get_enrollment_attributes(self.user.username, six.text_type(self.course.id)) + data.add_or_update_enrollment_attr(self.user.username, str(self.course.id), enrollment_attributes) + enrollment_attr = data.get_enrollment_attributes(self.user.username, str(self.course.id)) assert enrollment_attr[0] == enrollment_attributes[0] enrollment_attributes = [ @@ -303,8 +301,8 @@ class EnrollmentDataTest(ModuleStoreTestCase): } ] - data.add_or_update_enrollment_attr(self.user.username, six.text_type(self.course.id), enrollment_attributes) - enrollment_attr = data.get_enrollment_attributes(self.user.username, six.text_type(self.course.id)) + data.add_or_update_enrollment_attr(self.user.username, str(self.course.id), enrollment_attributes) + enrollment_attr = data.get_enrollment_attributes(self.user.username, str(self.course.id)) assert enrollment_attr[0] == enrollment_attributes[0] def test_non_existent_course(self): @@ -323,7 +321,7 @@ class EnrollmentDataTest(ModuleStoreTestCase): def test_enrollment_for_non_existent_user(self): with pytest.raises(UserNotFoundError): - data.create_course_enrollment("some_fake_user", six.text_type(self.course.id), 'honor', True) + data.create_course_enrollment("some_fake_user", str(self.course.id), 'honor', True) def test_enrollment_for_non_existent_course(self): with pytest.raises(CourseNotFoundError): @@ -333,23 +331,23 @@ class EnrollmentDataTest(ModuleStoreTestCase): def test_enrollment_for_closed_course(self, mock_enroll): mock_enroll.side_effect = EnrollmentClosedError("Bad things happened") with pytest.raises(CourseEnrollmentClosedError): - data.create_course_enrollment(self.user.username, six.text_type(self.course.id), 'honor', True) + data.create_course_enrollment(self.user.username, str(self.course.id), 'honor', True) @patch.object(CourseEnrollment, "enroll") def test_enrollment_for_full_course(self, mock_enroll): mock_enroll.side_effect = CourseFullError("Bad things happened") with pytest.raises(CourseEnrollmentFullError): - data.create_course_enrollment(self.user.username, six.text_type(self.course.id), 'honor', True) + data.create_course_enrollment(self.user.username, str(self.course.id), 'honor', True) @patch.object(CourseEnrollment, "enroll") def test_enrollment_for_enrolled_course(self, mock_enroll): mock_enroll.side_effect = AlreadyEnrolledError("Bad things happened") with pytest.raises(CourseEnrollmentExistsError): - data.create_course_enrollment(self.user.username, six.text_type(self.course.id), 'honor', True) + data.create_course_enrollment(self.user.username, str(self.course.id), 'honor', True) def test_update_for_non_existent_user(self): with pytest.raises(UserNotFoundError): - data.update_course_enrollment("some_fake_user", six.text_type(self.course.id), is_active=False) + data.update_course_enrollment("some_fake_user", str(self.course.id), is_active=False) def test_update_for_non_existent_course(self): enrollment = data.update_course_enrollment(self.user.username, "some/fake/course", is_active=False) @@ -378,7 +376,7 @@ class EnrollmentDataTest(ModuleStoreTestCase): def assert_enrollment_modes(self, expected_modes, include_expired): """Get enrollment data and assert response with expected modes.""" - result_course = data.get_course_enrollment_info(six.text_type(self.course.id), include_expired=include_expired) + result_course = data.get_course_enrollment_info(str(self.course.id), include_expired=include_expired) result_slugs = [mode['slug'] for mode in result_course['course_modes']] for course_mode in expected_modes: assert course_mode in result_slugs diff --git a/openedx/core/djangoapps/enrollments/tests/test_services.py b/openedx/core/djangoapps/enrollments/tests/test_services.py index 7ad37a5552..f8d14ba480 100644 --- a/openedx/core/djangoapps/enrollments/tests/test_services.py +++ b/openedx/core/djangoapps/enrollments/tests/test_services.py @@ -36,8 +36,8 @@ class EnrollmentsServiceTests(ModuleStoreTestCase): CourseModeFactory.create(mode_slug=course_mode, course_id=course_id) user = UserFactory( - username='user{}'.format(index), - email='LEARNER{}@example.com'.format(index) + username=f'user{index}', + email=f'LEARNER{index}@example.com' ) CourseEnrollment.enroll(user, course_id, mode=course_mode) @@ -186,7 +186,7 @@ class EnrollmentsServicePerformanceTests(ModuleStoreTestCase): def create_and_enroll_users(self, num_users): num_course_modes = len(self.course_modes) for index in range(num_users): - user = UserFactory(username='user{}'.format(index)) + user = UserFactory(username=f'user{index}') CourseEnrollment.enroll(user, self.course.id, mode=self.course_modes[index % num_course_modes]) @ddt.data(10, 25, 50) diff --git a/openedx/core/djangoapps/enrollments/tests/test_views.py b/openedx/core/djangoapps/enrollments/tests/test_views.py index 7c715954fb..d78922190b 100644 --- a/openedx/core/djangoapps/enrollments/tests/test_views.py +++ b/openedx/core/djangoapps/enrollments/tests/test_views.py @@ -8,11 +8,11 @@ import datetime import itertools import json import unittest +from unittest.mock import patch import pytest import ddt import httpretty import pytz -import six from django.conf import settings from django.core.cache import cache from django.core.exceptions import ImproperlyConfigured @@ -21,11 +21,8 @@ from django.test import Client from django.test.utils import override_settings from django.urls import reverse from freezegun import freeze_time -from mock import patch from rest_framework import status from rest_framework.test import APITestCase -from six import text_type -from six.moves import range from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.course_modes.tests.factories import CourseModeFactory @@ -50,7 +47,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls_range -class EnrollmentTestMixin(object): +class EnrollmentTestMixin: """ Mixin with methods useful for testing enrollments. """ API_KEY = "i am a key" @@ -76,7 +73,7 @@ class EnrollmentTestMixin(object): Returns Response """ - course_id = course_id or six.text_type(self.course.id) + course_id = course_id or str(self.course.id) username = username or self.user.username data = { @@ -171,7 +168,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente def setUp(self): """ Create a course and user, then log in. """ - super(EnrollmentTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.rate_limit_config = RateLimitConfiguration.current() self.rate_limit_config.enabled = False @@ -240,19 +237,19 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente resp = self.client.get( reverse( 'courseenrollment', - kwargs={'username': self.user.username, "course_id": six.text_type(self.course.id)}, + kwargs={'username': self.user.username, "course_id": str(self.course.id)}, ) ) assert resp.status_code == status.HTTP_200_OK data = json.loads(resp.content.decode('utf-8')) - assert six.text_type(self.course.id) == data['course_details']['course_id'] + assert str(self.course.id) == data['course_details']['course_id'] assert self.course.display_name_with_default == data['course_details']['course_name'] assert CourseMode.DEFAULT_MODE_SLUG == data['mode'] assert data['is_active'] @ddt.data( - (True, u"True"), - (False, u"False"), + (True, "True"), + (False, "False"), (None, None) ) @ddt.unpack @@ -289,7 +286,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente # While the enrollment wrong is invalid, the response content should have # all the valid enrollment modes. data = json.loads(resp.content.decode('utf-8')) - assert six.text_type(self.course.id) == data['course_details']['course_id'] + assert str(self.course.id) == data['course_details']['course_id'] assert 1 == len(data['course_details']['course_modes']) assert 'professional' == data['course_details']['course_modes'][0]['slug'] @@ -302,11 +299,11 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente # Create an enrollment self.assert_enrollment_status() resp = self.client.get( - reverse('courseenrollment', kwargs={"course_id": six.text_type(self.course.id)}) + reverse('courseenrollment', kwargs={"course_id": str(self.course.id)}) ) assert resp.status_code == status.HTTP_200_OK data = json.loads(resp.content.decode('utf-8')) - assert six.text_type(self.course.id) == data['course_details']['course_id'] + assert str(self.course.id) == data['course_details']['course_id'] assert CourseMode.DEFAULT_MODE_SLUG == data['mode'] assert data['is_active'] @@ -363,10 +360,9 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente response = self.client.get(reverse('courseenrollments'), {'user': self.user.username}, **kwargs) assert response.status_code == status.HTTP_200_OK data = json.loads(response.content.decode('utf-8')) - six.assertCountEqual( - self, + self.assertCountEqual( [(datum['course_details']['course_id'], datum['course_details']['course_name']) for datum in data], - [(six.text_type(course.id), course.display_name_with_default) for course in courses] + [(str(course.id), course.display_name_with_default) for course in courses] ) def test_enrollment_list_permissions(self): @@ -378,12 +374,12 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente other_course = CourseFactory.create(emit_signals=True) for course in self.course, other_course: CourseModeFactory.create( - course_id=six.text_type(course.id), + course_id=str(course.id), mode_slug=CourseMode.DEFAULT_MODE_SLUG, mode_display_name=CourseMode.DEFAULT_MODE_SLUG, ) self.assert_enrollment_status( - course_id=six.text_type(course.id), + course_id=str(course.id), max_mongo_calls=0, ) # Verify the user himself can see both of his enrollments. @@ -416,7 +412,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente mode_display_name=CourseMode.HONOR, ) url = reverse('courseenrollment', - kwargs={'username': self.other_user.username, "course_id": six.text_type(self.course.id)}) + kwargs={'username': self.other_user.username, "course_id": str(self.course.id)}) response = self.client.get(url) assert response.status_code == status.HTTP_404_NOT_FOUND @@ -441,12 +437,12 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente bulk_sku="BULK123" ) resp = self.client.get( - reverse('courseenrollmentdetails', kwargs={"course_id": six.text_type(self.course.id)}) + reverse('courseenrollmentdetails', kwargs={"course_id": str(self.course.id)}) ) assert resp.status_code == status.HTTP_200_OK data = json.loads(resp.content.decode('utf-8')) - assert six.text_type(self.course.id) == data['course_id'] + assert str(self.course.id) == data['course_id'] assert self.course.display_name_with_default == data['course_name'] mode = data['course_modes'][0] assert mode['slug'] == CourseMode.HONOR @@ -461,12 +457,12 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente mode_display_name=CourseMode.CREDIT_MODE, ) resp = self.client.get( - reverse('courseenrollmentdetails', kwargs={"course_id": six.text_type(self.course.id)}) + reverse('courseenrollmentdetails', kwargs={"course_id": str(self.course.id)}) ) assert resp.status_code == status.HTTP_200_OK data = json.loads(resp.content.decode('utf-8')) - assert six.text_type(self.course.id) == data['course_id'] + assert str(self.course.id) == data['course_id'] mode = data['course_modes'][0] assert mode['slug'] == CourseMode.CREDIT_MODE assert mode['name'] == CourseMode.CREDIT_MODE @@ -492,10 +488,10 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente # miss; the modulestore is queried and course metadata is cached. __ = CourseOverview.get_from_id(course.id) - self.assert_enrollment_status(course_id=six.text_type(course.id)) + self.assert_enrollment_status(course_id=str(course.id)) # Check course details - url = reverse('courseenrollmentdetails', kwargs={"course_id": six.text_type(course.id)}) + url = reverse('courseenrollmentdetails', kwargs={"course_id": str(course.id)}) resp = self.client.get(url) assert resp.status_code == status.HTTP_200_OK @@ -504,7 +500,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente assert data['course_end'] == expected_end # Check enrollment course details - url = reverse('courseenrollment', kwargs={"course_id": six.text_type(course.id)}) + url = reverse('courseenrollment', kwargs={"course_id": str(course.id)}) resp = self.client.get(url) assert resp.status_code == status.HTTP_200_OK @@ -540,7 +536,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente resp = self.client.get( reverse( 'courseenrollment', - kwargs={'username': self.user.username, "course_id": six.text_type(self.course.id)}, + kwargs={'username': self.user.username, "course_id": str(self.course.id)}, ) ) assert resp.status_code == status.HTTP_400_BAD_REQUEST @@ -592,7 +588,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente try: throttle.parse_rate(throttle.get_rate()) except ImproperlyConfigured: - self.fail(u"No throttle rate set for {}".format(user_scope)) + self.fail(f"No throttle rate set for {user_scope}") def test_create_enrollment_with_cohort(self): """Enroll in the course, and also add to a cohort.""" @@ -654,7 +650,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente v_response = self.client.get( reverse( 'courseenrollmentdetails', - kwargs={"course_id": six.text_type(self.course.id)} + kwargs={"course_id": str(self.course.id)} ), {'include_expired': True}, ) @@ -665,7 +661,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente # Omits the include_expired parameter from the API call h_response = self.client.get( - reverse('courseenrollmentdetails', kwargs={"course_id": six.text_type(self.course.id)}), + reverse('courseenrollmentdetails', kwargs={"course_id": str(self.course.id)}), ) h_data = json.loads(h_response.content.decode('utf-8')) @@ -1079,7 +1075,7 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase, Ente ) consent_kwargs = { 'username': self.user.username, - 'course_id': six.text_type(self.course.id), + 'course_id': str(self.course.id), 'ec_uuid': 'this-is-a-real-uuid' } mock_enterprise_customer_from_api.return_value = FAKE_ENTERPRISE_CUSTOMER @@ -1158,7 +1154,7 @@ class EnrollmentEmbargoTest(EnrollmentTestMixin, UrlResetMixin, ModuleStoreTestC @patch.dict(settings.FEATURES, {'EMBARGO': True}) def setUp(self): """ Create a course and user, then log in. """ - super(EnrollmentEmbargoTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create() # Load a CourseOverview. This initial load should result in a cache @@ -1172,7 +1168,7 @@ class EnrollmentEmbargoTest(EnrollmentTestMixin, UrlResetMixin, ModuleStoreTestC def _generate_data(self): return json.dumps({ 'course_details': { - 'course_id': six.text_type(self.course.id) + 'course_id': str(self.course.id) }, 'user': self.user.username }) @@ -1288,7 +1284,7 @@ class EnrollmentCrossDomainTest(ModuleStoreTestCase): def setUp(self): """ Create a course and user, then log in. """ - super(EnrollmentCrossDomainTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create() self.user = UserFactory.create(username=self.USERNAME, email=self.EMAIL, password=self.PASSWORD) @@ -1312,7 +1308,7 @@ class EnrollmentCrossDomainTest(ModuleStoreTestCase): def _get_csrf_cookie(self): """Retrieve the cross-domain CSRF cookie. """ url = reverse('courseenrollment', kwargs={ - 'course_id': six.text_type(self.course.id) + 'course_id': str(self.course.id) }) resp = self.client.get(url, HTTP_REFERER=self.REFERER) assert resp.status_code == 200 @@ -1324,7 +1320,7 @@ class EnrollmentCrossDomainTest(ModuleStoreTestCase): url = reverse('courseenrollments') params = json.dumps({ 'course_details': { - 'course_id': six.text_type(self.course.id), + 'course_id': str(self.course.id), }, 'user': self.user.username }) @@ -1351,7 +1347,7 @@ class UnenrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase): def setUp(self): """ Create a course and user, then log in. """ - super(UnenrollmentTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.superuser = SuperuserFactory() # Pass emit_signals when creating the course so it would be cached # as a CourseOverview. Enrollments require a cached CourseOverview. @@ -1431,7 +1427,7 @@ class UnenrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase): response = self._submit_unenroll(self.superuser, None) assert response.status_code == status.HTTP_404_NOT_FOUND data = json.loads(response.content.decode('utf-8')) - assert data == u'Username not specified.' + assert data == 'Username not specified.' self._assert_active() def test_deactivate_enrollments_empty_username(self): @@ -1495,7 +1491,7 @@ class UserRoleTest(ModuleStoreTestCase): def setUp(self): """ Create a course and user, then log in. """ - super(UserRoleTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course1 = CourseFactory.create(emit_signals=True, org="org1", course="course1", run="run1") self.course2 = CourseFactory.create(emit_signals=True, org="org2", course="course2", run="run2") self.user = UserFactory.create( @@ -1514,7 +1510,7 @@ class UserRoleTest(ModuleStoreTestCase): def _create_expected_role_dict(self, course, role): """ Creates the expected role dict object that the view should return """ return { - 'course_id': text_type(course.id), + 'course_id': str(course.id), 'org': course.org, 'role': role.ROLE, } @@ -1570,8 +1566,8 @@ class UserRoleTest(ModuleStoreTestCase): role2 = CourseStaffRole(self.course2.id) role2.add_users(self.user) expected_role2 = self._create_expected_role_dict(self.course2, role2) - self._assert_roles([expected_role1], False, course_id=text_type(self.course1.id)) - self._assert_roles([expected_role2], False, course_id=text_type(self.course2.id)) + self._assert_roles([expected_role1], False, course_id=str(self.course1.id)) + self._assert_roles([expected_role2], False, course_id=str(self.course2.id)) def test_roles_exception(self): with patch('openedx.core.djangoapps.enrollments.api.get_user_roles') as mock_get_user_roles: @@ -1580,7 +1576,7 @@ class UserRoleTest(ModuleStoreTestCase): assert response.status_code == status.HTTP_400_BAD_REQUEST expected_response = { "message": ( - u"An error occurred while retrieving roles for user '{username}" + "An error occurred while retrieving roles for user '{username}" ).format(username=self.user.username) } response_data = json.loads(response.content.decode('utf-8')) @@ -1596,7 +1592,7 @@ class CourseEnrollmentsApiListTest(APITestCase, ModuleStoreTestCase): CREATED_DATA = datetime.datetime(2018, 1, 1, 0, 0, 1, tzinfo=pytz.UTC) def setUp(self): - super(CourseEnrollmentsApiListTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.rate_limit_config = RateLimitConfiguration.current() self.rate_limit_config.enabled = False self.rate_limit_config.save() @@ -1641,31 +1637,31 @@ class CourseEnrollmentsApiListTest(APITestCase, ModuleStoreTestCase): with freeze_time(self.CREATED_DATA): data.create_course_enrollment( self.student1.username, - six.text_type(self.course.id), + str(self.course.id), 'honor', True ) data.create_course_enrollment( self.student2.username, - six.text_type(self.course.id), + str(self.course.id), 'honor', True ) data.create_course_enrollment( self.student3.username, - six.text_type(self.course2.id), + str(self.course2.id), 'verified', True ) data.create_course_enrollment( self.student2.username, - six.text_type(self.course2.id), + str(self.course2.id), 'honor', True ) data.create_course_enrollment( self.staff_user.username, - six.text_type(self.course2.id), + str(self.course2.id), 'verified', True ) @@ -1742,4 +1738,4 @@ class CourseEnrollmentsApiListTest(APITestCase, ModuleStoreTestCase): content = self._assert_list_of_enrollments(query_params, status.HTTP_200_OK) results = content['results'] - six.assertCountEqual(self, results, expected_results) + self.assertCountEqual(results, expected_results) diff --git a/openedx/core/djangoapps/enrollments/urls.py b/openedx/core/djangoapps/enrollments/urls.py index 719701f0ef..f50221bae0 100644 --- a/openedx/core/djangoapps/enrollments/urls.py +++ b/openedx/core/djangoapps/enrollments/urls.py @@ -21,11 +21,11 @@ urlpatterns = [ username=settings.USERNAME_PATTERN, course_key=settings.COURSE_ID_PATTERN), EnrollmentView.as_view(), name='courseenrollment'), - url(r'^enrollment/{course_key}$'.format(course_key=settings.COURSE_ID_PATTERN), + url(fr'^enrollment/{settings.COURSE_ID_PATTERN}$', EnrollmentView.as_view(), name='courseenrollment'), url(r'^enrollment$', EnrollmentListView.as_view(), name='courseenrollments'), url(r'^enrollments/?$', CourseEnrollmentsApiListView.as_view(), name='courseenrollmentsapilist'), - url(r'^course/{course_key}$'.format(course_key=settings.COURSE_ID_PATTERN), + url(fr'^course/{settings.COURSE_ID_PATTERN}$', EnrollmentCourseDetailView.as_view(), name='courseenrollmentdetails'), url(r'^unenroll/$', UnenrollmentView.as_view(), name='unenrollment'), url(r'^roles/$', EnrollmentUserRolesView.as_view(), name='roles'), diff --git a/openedx/core/djangoapps/enrollments/views.py b/openedx/core/djangoapps/enrollments/views.py index 3de3236e9f..af48f24426 100644 --- a/openedx/core/djangoapps/enrollments/views.py +++ b/openedx/core/djangoapps/enrollments/views.py @@ -7,8 +7,6 @@ consist primarily of authentication, request validation, and serialization. import logging -from six import text_type - from common.djangoapps.course_modes.models import CourseMode from django.core.exceptions import ObjectDoesNotExist, ValidationError # lint-amnesty, pylint: disable=wrong-import-order from django.utils.decorators import method_decorator # lint-amnesty, pylint: disable=wrong-import-order @@ -62,7 +60,7 @@ class EnrollmentCrossDomainSessionAuth(SessionAuthenticationAllowInactiveUser, S pass # lint-amnesty, pylint: disable=unnecessary-pass -class ApiKeyPermissionMixIn(object): +class ApiKeyPermissionMixIn: """ This mixin is used to provide a convenience function for doing individual permission checks for the presence of API keys. @@ -99,7 +97,7 @@ class EnrollmentUserThrottle(UserRateThrottle, ApiKeyPermissionMixIn): self.rate = self.get_rate() self.num_requests, self.duration = self.parse_rate(self.rate) - return self.has_api_key_permissions(request) or super(EnrollmentUserThrottle, self).allow_request(request, view) # lint-amnesty, pylint: disable=super-with-arguments + return self.has_api_key_permissions(request) or super().allow_request(request, view) @can_disable_rate_limit @@ -210,8 +208,8 @@ class EnrollmentView(APIView, ApiKeyPermissionMixIn): status=status.HTTP_400_BAD_REQUEST, data={ "message": ( - u"An error occurred while retrieving enrollments for user " - u"'{username}' in course '{course_id}'" + "An error occurred while retrieving enrollments for user " + "'{username}' in course '{course_id}'" ).format(username=username, course_id=course_id) } ) @@ -258,13 +256,13 @@ class EnrollmentUserRolesView(APIView): course_id = request.GET.get('course_id') roles_data = api.get_user_roles(request.user.username) if course_id: - roles_data = [role for role in roles_data if text_type(role.course_id) == course_id] + roles_data = [role for role in roles_data if str(role.course_id) == course_id] except Exception: # pylint: disable=broad-except return Response( status=status.HTTP_400_BAD_REQUEST, data={ "message": ( - u"An error occurred while retrieving roles for user '{username}" + "An error occurred while retrieving roles for user '{username}" ).format(username=request.user.username) } ) @@ -272,7 +270,7 @@ class EnrollmentUserRolesView(APIView): 'roles': [ { "org": role.org, - "course_id": text_type(role.course_id), + "course_id": str(role.course_id), "role": role.role } for role in roles_data], @@ -370,7 +368,7 @@ class EnrollmentCourseDetailView(APIView): status=status.HTTP_400_BAD_REQUEST, data={ "message": ( - u"No course found for course ID '{course_id}'" + "No course found for course ID '{course_id}'" ).format(course_id=course_id) } ) @@ -429,11 +427,11 @@ class UnenrollmentView(APIView): return Response(status=status.HTTP_204_NO_CONTENT) return Response(api.unenroll_user_from_all_courses(username)) except KeyError: - return Response(u'Username not specified.', status=status.HTTP_404_NOT_FOUND) + return Response('Username not specified.', status=status.HTTP_404_NOT_FOUND) except UserRetirementStatus.DoesNotExist: - return Response(u'No retirement request status for username.', status=status.HTTP_404_NOT_FOUND) + return Response('No retirement request status for username.', status=status.HTTP_404_NOT_FOUND) except Exception as exc: # pylint: disable=broad-except - return Response(text_type(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR) + return Response(str(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR) @can_disable_rate_limit @@ -647,7 +645,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): status=status.HTTP_400_BAD_REQUEST, data={ "message": ( - u"An error occurred while retrieving enrollments for user '{username}'" + "An error occurred while retrieving enrollments for user '{username}'" ).format(username=username) } ) @@ -676,7 +674,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): if not course_id: return Response( status=status.HTTP_400_BAD_REQUEST, - data={"message": u"Course ID must be specified to create a new enrollment."} + data={"message": "Course ID must be specified to create a new enrollment."} ) try: @@ -685,7 +683,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): return Response( status=status.HTTP_400_BAD_REQUEST, data={ - "message": u"No course '{course_id}' found for enrollment".format(course_id=course_id) + "message": f"No course '{course_id}' found for enrollment" } ) @@ -707,7 +705,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): return Response( status=status.HTTP_403_FORBIDDEN, data={ - "message": u"User does not have permission to create enrollment with mode [{mode}].".format( + "message": "User does not have permission to create enrollment with mode [{mode}].".format( mode=mode ) } @@ -720,7 +718,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): return Response( status=status.HTTP_406_NOT_ACCEPTABLE, data={ - 'message': u'The user {} does not exist.'.format(username) + 'message': f'The user {username} does not exist.' } ) @@ -736,7 +734,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): return Response( status=status.HTTP_400_BAD_REQUEST, data={ - 'message': (u"'{value}' is an invalid enrollment activation status.").format(value=is_active) + 'message': ("'{value}' is an invalid enrollment activation status.").format(value=is_active) } ) @@ -745,26 +743,26 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): enterprise_api_client = EnterpriseApiServiceClient() consent_client = ConsentApiServiceClient() try: - enterprise_api_client.post_enterprise_course_enrollment(username, text_type(course_id), None) + enterprise_api_client.post_enterprise_course_enrollment(username, str(course_id), None) except EnterpriseApiException as error: - log.exception(u"An unexpected error occurred while creating the new EnterpriseCourseEnrollment " - u"for user [%s] in course run [%s]", username, course_id) - raise CourseEnrollmentError(text_type(error)) # lint-amnesty, pylint: disable=raise-missing-from + log.exception("An unexpected error occurred while creating the new EnterpriseCourseEnrollment " + "for user [%s] in course run [%s]", username, course_id) + raise CourseEnrollmentError(str(error)) # lint-amnesty, pylint: disable=raise-missing-from kwargs = { 'username': username, - 'course_id': text_type(course_id), + 'course_id': str(course_id), 'enterprise_customer_uuid': explicit_linked_enterprise, } consent_client.provide_consent(**kwargs) enrollment_attributes = request.data.get('enrollment_attributes') - enrollment = api.get_enrollment(username, text_type(course_id)) + enrollment = api.get_enrollment(username, str(course_id)) mode_changed = enrollment and mode is not None and enrollment['mode'] != mode active_changed = enrollment and is_active is not None and enrollment['is_active'] != is_active missing_attrs = [] if enrollment_attributes: actual_attrs = [ - u"{namespace}:{name}".format(**attr) + "{namespace}:{name}".format(**attr) for attr in enrollment_attributes ] missing_attrs = set(REQUIRED_ATTRIBUTES.get(mode, [])) - set(actual_attrs) @@ -773,14 +771,14 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): # if the requester wanted to deactivate but specified the wrong mode, fail # the request (on the assumption that the requester had outdated information # about the currently active enrollment). - msg = u"Enrollment mode mismatch: active mode={}, requested mode={}. Won't deactivate.".format( + msg = "Enrollment mode mismatch: active mode={}, requested mode={}. Won't deactivate.".format( enrollment["mode"], mode ) log.warning(msg) return Response(status=status.HTTP_400_BAD_REQUEST, data={"message": msg}) if missing_attrs: - msg = u"Missing enrollment attributes: requested mode={} required attributes={}".format( + msg = "Missing enrollment attributes: requested mode={} required attributes={}".format( mode, REQUIRED_ATTRIBUTES.get(mode) ) log.warning(msg) @@ -788,7 +786,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): response = api.update_enrollment( username, - text_type(course_id), + str(course_id), mode=mode, is_active=is_active, enrollment_attributes=enrollment_attributes, @@ -799,7 +797,7 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): # Will reactivate inactive enrollments. response = api.add_enrollment( username, - text_type(course_id), + str(course_id), mode=mode, is_active=is_active, enrollment_attributes=enrollment_attributes @@ -818,14 +816,14 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): org = course_id.org update_email_opt_in(request.user, org, email_opt_in) - log.info(u'The user [%s] has already been enrolled in course run [%s].', username, course_id) + log.info('The user [%s] has already been enrolled in course run [%s].', username, course_id) return Response(response) except CourseModeNotFoundError as error: return Response( status=status.HTTP_400_BAD_REQUEST, data={ "message": ( - u"The [{mode}] course mode is expired or otherwise unavailable for course run [{course_id}]." + "The [{mode}] course mode is expired or otherwise unavailable for course run [{course_id}]." ).format(mode=mode, course_id=course_id), "course_details": error.data }) @@ -833,38 +831,38 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): return Response( status=status.HTTP_400_BAD_REQUEST, data={ - "message": u"No course '{course_id}' found for enrollment".format(course_id=course_id) + "message": f"No course '{course_id}' found for enrollment" } ) except CourseEnrollmentExistsError as error: - log.warning(u'An enrollment already exists for user [%s] in course run [%s].', username, course_id) + log.warning('An enrollment already exists for user [%s] in course run [%s].', username, course_id) return Response(data=error.enrollment) except CourseEnrollmentError: - log.exception(u"An error occurred while creating the new course enrollment for user " - u"[%s] in course run [%s]", username, course_id) + log.exception("An error occurred while creating the new course enrollment for user " + "[%s] in course run [%s]", username, course_id) return Response( status=status.HTTP_400_BAD_REQUEST, data={ "message": ( - u"An error occurred while creating the new course enrollment for user " - u"'{username}' in course '{course_id}'" + "An error occurred while creating the new course enrollment for user " + "'{username}' in course '{course_id}'" ).format(username=username, course_id=course_id) } ) except CourseUserGroup.DoesNotExist: - log.exception(u'Missing cohort [%s] in course run [%s]', cohort_name, course_id) + log.exception('Missing cohort [%s] in course run [%s]', cohort_name, course_id) return Response( status=status.HTTP_400_BAD_REQUEST, data={ - "message": u"An error occured while adding to cohort [%s]" % cohort_name + "message": "An error occured while adding to cohort [%s]" % cohort_name }) finally: # Assumes that the ecommerce service uses an API key to authenticate. if has_api_key_permissions: - current_enrollment = api.get_enrollment(username, text_type(course_id)) + current_enrollment = api.get_enrollment(username, str(course_id)) audit_log( 'enrollment_change_requested', - course_id=text_type(course_id), + course_id=str(course_id), requested_mode=mode, actual_mode=current_enrollment['mode'] if current_enrollment else None, requested_activation=is_active,