diff --git a/common/djangoapps/course_modes/admin.py b/common/djangoapps/course_modes/admin.py index c6419d241bf4af6eef8dab673b2278aceb9eaef9..74a9d2892e723e6b61edd638748a4185200a865c 100644 --- a/common/djangoapps/course_modes/admin.py +++ b/common/djangoapps/course_modes/admin.py @@ -26,7 +26,7 @@ from openedx.core.lib.courses import clean_course_id from common.djangoapps.util.date_utils import get_time_display COURSE_MODE_SLUG_CHOICES = [(key, enrollment_mode['display_name']) - for key, enrollment_mode in six.iteritems(settings.COURSE_ENROLLMENT_MODES)] + for key, enrollment_mode in settings.COURSE_ENROLLMENT_MODES.items()] class CourseModeForm(forms.ModelForm): @@ -34,7 +34,7 @@ class CourseModeForm(forms.ModelForm): Admin form for adding a course mode. """ - class Meta(object): + class Meta: model = CourseMode fields = '__all__' @@ -63,7 +63,7 @@ class CourseModeForm(forms.ModelForm): args_copy['course'] = CourseKey.from_string(args_copy['course']) args = [args_copy] - super(CourseModeForm, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) try: if self.data.get('course'): @@ -122,7 +122,7 @@ class CourseModeForm(forms.ModelForm): Clean the form fields. This is the place to perform checks that involve multiple form fields. """ - cleaned_data = super(CourseModeForm, self).clean() # lint-amnesty, pylint: disable=super-with-arguments + cleaned_data = super().clean() mode_slug = cleaned_data.get("mode_slug") upgrade_deadline = cleaned_data.get("_expiration_datetime") verification_deadline = cleaned_data.get("verification_deadline") @@ -173,7 +173,7 @@ class CourseModeForm(forms.ModelForm): verification_deadline ) - return super(CourseModeForm, self).save(commit=commit) # lint-amnesty, pylint: disable=super-with-arguments + return super().save(commit=commit) @admin.register(CourseMode) diff --git a/common/djangoapps/course_modes/helpers.py b/common/djangoapps/course_modes/helpers.py index c3f26bc19abe12407340702f84278e8734206a49..4511a32ffdcacb118a1e30851209e30f9fffa335 100644 --- a/common/djangoapps/course_modes/helpers.py +++ b/common/djangoapps/course_modes/helpers.py @@ -58,10 +58,10 @@ def enrollment_mode_display(mode, verification_status, course_id): enrollment_value = _("Professional Ed") return { - 'enrollment_title': six.text_type(enrollment_title), - 'enrollment_value': six.text_type(enrollment_value), + 'enrollment_title': str(enrollment_title), + 'enrollment_value': str(enrollment_value), 'show_image': show_image, - 'image_alt': six.text_type(image_alt), + 'image_alt': str(image_alt), 'display_mode': _enrollment_mode_display(mode, verification_status, course_id) } diff --git a/common/djangoapps/course_modes/migrations/0001_initial.py b/common/djangoapps/course_modes/migrations/0001_initial.py index 094f8a037b6a92dd2cc68cccf42fa29766771c4b..6caeedc04af7a25f680ceba877e04cec20b224e1 100644 --- a/common/djangoapps/course_modes/migrations/0001_initial.py +++ b/common/djangoapps/course_modes/migrations/0001_initial.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - from django.db import migrations, models from opaque_keys.edx.django.models import CourseKeyField @@ -19,12 +16,12 @@ class Migration(migrations.Migration): ('mode_slug', models.CharField(max_length=100, verbose_name='Mode')), ('mode_display_name', models.CharField(max_length=255, verbose_name='Display Name')), ('min_price', models.IntegerField(default=0, verbose_name='Price')), - ('currency', models.CharField(default=u'usd', max_length=8)), + ('currency', models.CharField(default='usd', max_length=8)), ('expiration_datetime', models.DateTimeField(default=None, help_text='OPTIONAL: After this date/time, users will no longer be able to enroll in this mode. Leave this blank if users can enroll in this mode until enrollment closes for the course.', null=True, verbose_name='Upgrade Deadline', blank=True)), ('expiration_date', models.DateField(default=None, null=True, blank=True)), - ('suggested_prices', models.CommaSeparatedIntegerField(default=u'', max_length=255, blank=True)), + ('suggested_prices', models.CommaSeparatedIntegerField(default='', max_length=255, blank=True)), ('description', models.TextField(null=True, blank=True)), - ('sku', models.CharField(help_text='OPTIONAL: This is the SKU (stock keeping unit) of this mode in the external ecommerce service. Leave this blank if the course has not yet been migrated to the ecommerce service.', max_length=255, null=True, verbose_name=u'SKU', blank=True)), + ('sku', models.CharField(help_text='OPTIONAL: This is the SKU (stock keeping unit) of this mode in the external ecommerce service. Leave this blank if the course has not yet been migrated to the ecommerce service.', max_length=255, null=True, verbose_name='SKU', blank=True)), ], ), migrations.CreateModel( @@ -35,14 +32,14 @@ class Migration(migrations.Migration): ('mode_slug', models.CharField(max_length=100)), ('mode_display_name', models.CharField(max_length=255)), ('min_price', models.IntegerField(default=0)), - ('suggested_prices', models.CommaSeparatedIntegerField(default=u'', max_length=255, blank=True)), - ('currency', models.CharField(default=u'usd', max_length=8)), + ('suggested_prices', models.CommaSeparatedIntegerField(default='', max_length=255, blank=True)), + ('currency', models.CharField(default='usd', max_length=8)), ('expiration_date', models.DateField(default=None, null=True, blank=True)), ('expiration_datetime', models.DateTimeField(default=None, null=True, blank=True)), ], ), migrations.AlterUniqueTogether( name='coursemode', - unique_together=set([('course_id', 'mode_slug', 'currency')]), + unique_together={('course_id', 'mode_slug', 'currency')}, ), ] diff --git a/common/djangoapps/course_modes/migrations/0002_coursemode_expiration_datetime_is_explicit.py b/common/djangoapps/course_modes/migrations/0002_coursemode_expiration_datetime_is_explicit.py index 86124fc13cf3d68a9db5beef1a9932d377200ba4..46ba65c1f7d108983b956a91004cd56e387f3303 100644 --- a/common/djangoapps/course_modes/migrations/0002_coursemode_expiration_datetime_is_explicit.py +++ b/common/djangoapps/course_modes/migrations/0002_coursemode_expiration_datetime_is_explicit.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - from django.db import migrations, models diff --git a/common/djangoapps/course_modes/migrations/0003_auto_20151113_1443.py b/common/djangoapps/course_modes/migrations/0003_auto_20151113_1443.py index c65f5932dcab483a52cdd6c33ec85f3e0dfc4a15..8a7bb9231c30b9a328f4de32542d12c329796695 100644 --- a/common/djangoapps/course_modes/migrations/0003_auto_20151113_1443.py +++ b/common/djangoapps/course_modes/migrations/0003_auto_20151113_1443.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - from django.db import migrations, models diff --git a/common/djangoapps/course_modes/migrations/0004_auto_20151113_1457.py b/common/djangoapps/course_modes/migrations/0004_auto_20151113_1457.py index 24e842eb7eae5c5d41cc30cd23f55ecfeba4edac..34d173fc191ef86e8abd04163281223566e5d3c3 100644 --- a/common/djangoapps/course_modes/migrations/0004_auto_20151113_1457.py +++ b/common/djangoapps/course_modes/migrations/0004_auto_20151113_1457.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - from datetime import timedelta import django.db.models.deletion diff --git a/common/djangoapps/course_modes/migrations/0005_auto_20151217_0958.py b/common/djangoapps/course_modes/migrations/0005_auto_20151217_0958.py index 2842c255b8a4ccd9b2f39ae0bd355a23908aebb2..d30a951c6fd07bcb997b351ffcf95376798734b0 100644 --- a/common/djangoapps/course_modes/migrations/0005_auto_20151217_0958.py +++ b/common/djangoapps/course_modes/migrations/0005_auto_20151217_0958.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - from django.db import migrations, models @@ -21,7 +18,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='coursemode', name='_expiration_datetime', - field=models.DateTimeField(db_column=u'expiration_datetime', default=None, blank=True, help_text='OPTIONAL: After this date/time, users will no longer be able to enroll in this mode. Leave this blank if users can enroll in this mode until enrollment closes for the course.', null=True, verbose_name='Upgrade Deadline'), + field=models.DateTimeField(db_column='expiration_datetime', default=None, blank=True, help_text='OPTIONAL: After this date/time, users will no longer be able to enroll in this mode. Leave this blank if users can enroll in this mode until enrollment closes for the course.', null=True, verbose_name='Upgrade Deadline'), ), ] ) diff --git a/common/djangoapps/course_modes/migrations/0006_auto_20160208_1407.py b/common/djangoapps/course_modes/migrations/0006_auto_20160208_1407.py index 6cc63a3a6b6153fbb5a5b32b5ebc94716dea52a6..02f5f81bafe37ced0b114c7ef92c024ae6540ac2 100644 --- a/common/djangoapps/course_modes/migrations/0006_auto_20160208_1407.py +++ b/common/djangoapps/course_modes/migrations/0006_auto_20160208_1407.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - from django.db import migrations, models diff --git a/common/djangoapps/course_modes/migrations/0007_coursemode_bulk_sku.py b/common/djangoapps/course_modes/migrations/0007_coursemode_bulk_sku.py index f82e852807a44704e6685c07a3ec89311f493501..c36111c5cd80212e5708aa1478cf41980f80f9e0 100644 --- a/common/djangoapps/course_modes/migrations/0007_coursemode_bulk_sku.py +++ b/common/djangoapps/course_modes/migrations/0007_coursemode_bulk_sku.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - from django.db import migrations, models @@ -14,6 +11,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='coursemode', name='bulk_sku', - field=models.CharField(default=None, max_length=255, blank=True, help_text='This is the bulk SKU (stock keeping unit) of this mode in the external ecommerce service.', null=True, verbose_name=u'Bulk SKU'), + field=models.CharField(default=None, max_length=255, blank=True, help_text='This is the bulk SKU (stock keeping unit) of this mode in the external ecommerce service.', null=True, verbose_name='Bulk SKU'), ), ] diff --git a/common/djangoapps/course_modes/migrations/0008_course_key_field_to_foreign_key.py b/common/djangoapps/course_modes/migrations/0008_course_key_field_to_foreign_key.py index b844e4009d52936584ceb6e6a3451a1290e4e056..7c4734f995b0c5fd6aed07175ee6d02872dd8089 100644 --- a/common/djangoapps/course_modes/migrations/0008_course_key_field_to_foreign_key.py +++ b/common/djangoapps/course_modes/migrations/0008_course_key_field_to_foreign_key.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - from django.db import migrations, models from opaque_keys.edx.django.models import CourseKeyField @@ -52,6 +49,6 @@ class Migration(migrations.Migration): # since the database column constraint already exists). migrations.AlterUniqueTogether( name='coursemode', - unique_together=set([('course', 'mode_slug', 'currency')]), + unique_together={('course', 'mode_slug', 'currency')}, ), ] diff --git a/common/djangoapps/course_modes/migrations/0009_suggested_prices_to_charfield.py b/common/djangoapps/course_modes/migrations/0009_suggested_prices_to_charfield.py index 66e5ef5391fe2c168e8ef1c39cb831a90a98d22b..628020196b2170612a13c210a09f53be1f607bd6 100644 --- a/common/djangoapps/course_modes/migrations/0009_suggested_prices_to_charfield.py +++ b/common/djangoapps/course_modes/migrations/0009_suggested_prices_to_charfield.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - import re import django.core.validators @@ -17,6 +14,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='coursemode', name='suggested_prices', - field=models.CharField(default=u'', max_length=255, blank=True, validators=[django.core.validators.RegexValidator(re.compile('^[\\d,]+\\Z'), 'Enter only digits separated by commas.', 'invalid')]), + field=models.CharField(default='', max_length=255, blank=True, validators=[django.core.validators.RegexValidator(re.compile('^[\\d,]+\\Z'), 'Enter only digits separated by commas.', 'invalid')]), ), ] diff --git a/common/djangoapps/course_modes/migrations/0010_archived_suggested_prices_to_charfield.py b/common/djangoapps/course_modes/migrations/0010_archived_suggested_prices_to_charfield.py index 979b75afb264b31cbcde9e7e24a7c282bb830d5a..d534d900103aa7f37b8a7fb529ca279c1ec5d64c 100644 --- a/common/djangoapps/course_modes/migrations/0010_archived_suggested_prices_to_charfield.py +++ b/common/djangoapps/course_modes/migrations/0010_archived_suggested_prices_to_charfield.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- - - import re import django.core.validators @@ -17,6 +14,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='coursemodesarchive', name='suggested_prices', - field=models.CharField(default=u'', max_length=255, blank=True, validators=[django.core.validators.RegexValidator(re.compile('^[\\d,]+\\Z'), 'Enter only digits separated by commas.', 'invalid')]), + field=models.CharField(default='', max_length=255, blank=True, validators=[django.core.validators.RegexValidator(re.compile('^[\\d,]+\\Z'), 'Enter only digits separated by commas.', 'invalid')]), ), ] diff --git a/common/djangoapps/course_modes/migrations/0011_change_regex_for_comma_separated_ints.py b/common/djangoapps/course_modes/migrations/0011_change_regex_for_comma_separated_ints.py index 6d3c9d288580bac62ce5aa7cca98572e5771ca1a..add4c005205cb611eebef02d0ca18a2178f9a6cd 100644 --- a/common/djangoapps/course_modes/migrations/0011_change_regex_for_comma_separated_ints.py +++ b/common/djangoapps/course_modes/migrations/0011_change_regex_for_comma_separated_ints.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.8 on 2018-01-30 17:38 @@ -18,11 +17,11 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='coursemode', name='suggested_prices', - field=models.CharField(blank=True, default=u'', max_length=255, validators=[django.core.validators.RegexValidator(re.compile('^\d+(?:{escaped_comma}\d+)*\Z'.format(escaped_comma=re.escape(','))), code='invalid', message='Enter only digits separated by commas.')]), + field=models.CharField(blank=True, default='', max_length=255, validators=[django.core.validators.RegexValidator(re.compile(r'^\d+(?:{escaped_comma}\d+)*\Z'.format(escaped_comma=re.escape(','))), code='invalid', message='Enter only digits separated by commas.')]), ), migrations.AlterField( model_name='coursemodesarchive', name='suggested_prices', - field=models.CharField(blank=True, default=u'', max_length=255, validators=[django.core.validators.RegexValidator(re.compile('^\d+(?:{escaped_comma}\d+)*\Z'.format(escaped_comma=re.escape(','))), code='invalid', message='Enter only digits separated by commas.')]), + field=models.CharField(blank=True, default='', max_length=255, validators=[django.core.validators.RegexValidator(re.compile(r'^\d+(?:{escaped_comma}\d+)*\Z'.format(escaped_comma=re.escape(','))), code='invalid', message='Enter only digits separated by commas.')]), ), ] diff --git a/common/djangoapps/course_modes/migrations/0012_historicalcoursemode.py b/common/djangoapps/course_modes/migrations/0012_historicalcoursemode.py index e59956d9448672a9ce3de71dfd116a957b0cb822..48d0a39cf4ce8af673f0df0c189a621649a1471a 100644 --- a/common/djangoapps/course_modes/migrations/0012_historicalcoursemode.py +++ b/common/djangoapps/course_modes/migrations/0012_historicalcoursemode.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.21 on 2019-06-19 01:31 @@ -26,14 +25,14 @@ class Migration(migrations.Migration): ('mode_slug', models.CharField(max_length=100, verbose_name='Mode')), ('mode_display_name', models.CharField(max_length=255, verbose_name='Display Name')), ('min_price', models.IntegerField(default=0, verbose_name='Price')), - ('currency', models.CharField(default=u'usd', max_length=8)), - ('_expiration_datetime', models.DateTimeField(blank=True, db_column=u'expiration_datetime', default=None, help_text='OPTIONAL: After this date/time, users will no longer be able to enroll in this mode. Leave this blank if users can enroll in this mode until enrollment closes for the course.', null=True, verbose_name='Upgrade Deadline')), + ('currency', models.CharField(default='usd', max_length=8)), + ('_expiration_datetime', models.DateTimeField(blank=True, db_column='expiration_datetime', default=None, help_text='OPTIONAL: After this date/time, users will no longer be able to enroll in this mode. Leave this blank if users can enroll in this mode until enrollment closes for the course.', null=True, verbose_name='Upgrade Deadline')), ('expiration_datetime_is_explicit', models.BooleanField(default=False)), ('expiration_date', models.DateField(blank=True, default=None, null=True)), - ('suggested_prices', models.CharField(blank=True, default=u'', max_length=255, validators=[django.core.validators.RegexValidator(re.compile('^\\d+(?:{escaped_comma}\\d+)*\\Z'.format(escaped_comma=re.escape(','))), code='invalid', message='Enter only digits separated by commas.')])), + ('suggested_prices', models.CharField(blank=True, default='', max_length=255, validators=[django.core.validators.RegexValidator(re.compile('^\\d+(?:{escaped_comma}\\d+)*\\Z'.format(escaped_comma=re.escape(','))), code='invalid', message='Enter only digits separated by commas.')])), ('description', models.TextField(blank=True, null=True)), - ('sku', models.CharField(blank=True, help_text='OPTIONAL: This is the SKU (stock keeping unit) of this mode in the external ecommerce service. Leave this blank if the course has not yet been migrated to the ecommerce service.', max_length=255, null=True, verbose_name=u'SKU')), - ('bulk_sku', models.CharField(blank=True, default=None, help_text='This is the bulk SKU (stock keeping unit) of this mode in the external ecommerce service.', max_length=255, null=True, verbose_name=u'Bulk SKU')), + ('sku', models.CharField(blank=True, help_text='OPTIONAL: This is the SKU (stock keeping unit) of this mode in the external ecommerce service. Leave this blank if the course has not yet been migrated to the ecommerce service.', max_length=255, null=True, verbose_name='SKU')), + ('bulk_sku', models.CharField(blank=True, default=None, help_text='This is the bulk SKU (stock keeping unit) of this mode in the external ecommerce service.', max_length=255, null=True, verbose_name='Bulk SKU')), ('history_id', models.AutoField(primary_key=True, serialize=False)), ('history_date', models.DateTimeField()), ('history_change_reason', models.CharField(max_length=100, null=True)), diff --git a/common/djangoapps/course_modes/migrations/0013_auto_20200115_2022.py b/common/djangoapps/course_modes/migrations/0013_auto_20200115_2022.py index 31391335656e83e9d2d43e9df4d593fa160b4593..eb89c2a9bb55d67f15e0f4ad7d37e94f31496d69 100644 --- a/common/djangoapps/course_modes/migrations/0013_auto_20200115_2022.py +++ b/common/djangoapps/course_modes/migrations/0013_auto_20200115_2022.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.11.27 on 2020-01-15 20:22 diff --git a/common/djangoapps/course_modes/models.py b/common/djangoapps/course_modes/models.py index 82552ed531b5a3a8d352cfd4885e738c1ff3d208..c9972cd93dc8c55b332b25778064375e3df6601b 100644 --- a/common/djangoapps/course_modes/models.py +++ b/common/djangoapps/course_modes/models.py @@ -69,7 +69,7 @@ class CourseMode(models.Model): min_price = models.IntegerField(default=0, verbose_name=_("Price")) # the currency these prices are in, using lower case ISO currency codes - currency = models.CharField(default=u"usd", max_length=8) + currency = models.CharField(default="usd", max_length=8) # The datetime at which the course mode will expire. # This is used to implement "upgrade" deadlines. @@ -78,12 +78,12 @@ class CourseMode(models.Model): # Once the date passes, users will no longer be able to enroll as verified. _expiration_datetime = models.DateTimeField( default=None, null=True, blank=True, - verbose_name=_(u"Upgrade Deadline"), + verbose_name=_("Upgrade Deadline"), help_text=_( - u"OPTIONAL: After this date/time, users will no longer be able to enroll in this mode. " - u"Leave this blank if users can enroll in this mode until enrollment closes for the course." + "OPTIONAL: After this date/time, users will no longer be able to enroll in this mode. " + "Leave this blank if users can enroll in this mode until enrollment closes for the course." ), - db_column=u'expiration_datetime', + db_column='expiration_datetime', ) # The system prefers to set this automatically based on default settings. But @@ -97,7 +97,7 @@ class CourseMode(models.Model): # DEPRECATED: the suggested prices for this mode # We used to allow users to choose from a set of prices, but we now allow only # a single price. This field has been deprecated by `min_price` - suggested_prices = models.CharField(max_length=255, blank=True, default=u'', + suggested_prices = models.CharField(max_length=255, blank=True, default='', validators=[validate_comma_separated_integer_list]) # optional description override @@ -109,10 +109,10 @@ class CourseMode(models.Model): max_length=255, null=True, blank=True, - verbose_name=u"SKU", + verbose_name="SKU", help_text=_( - u"OPTIONAL: This is the SKU (stock keeping unit) of this mode in the external ecommerce service. " - u"Leave this blank if the course has not yet been migrated to the ecommerce service." + "OPTIONAL: This is the SKU (stock keeping unit) of this mode in the external ecommerce service. " + "Leave this blank if the course has not yet been migrated to the ecommerce service." ) ) @@ -122,9 +122,9 @@ class CourseMode(models.Model): null=True, blank=True, default=None, # Need this in order to set DEFAULT NULL on the database column - verbose_name=u"Bulk SKU", + verbose_name="Bulk SKU", help_text=_( - u"This is the bulk SKU (stock keeping unit) of this mode in the external ecommerce service." + "This is the bulk SKU (stock keeping unit) of this mode in the external ecommerce service." ) ) @@ -184,14 +184,14 @@ class CourseMode(models.Model): # Modes that are allowed to upsell UPSELL_TO_VERIFIED_MODES = [HONOR, AUDIT] - CACHE_NAMESPACE = u"course_modes.CourseMode.cache." + CACHE_NAMESPACE = "course_modes.CourseMode.cache." - class Meta(object): + class Meta: app_label = "course_modes" unique_together = ('course', 'mode_slug', 'currency') def __init__(self, *args, **kwargs): # lint-amnesty, pylint: disable=useless-super-delegation - super(CourseMode, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) def clean(self): """ @@ -200,7 +200,7 @@ class CourseMode(models.Model): """ if self.is_professional_slug(self.mode_slug) and self.expiration_datetime is not None: raise ValidationError( - _(u"Professional education modes are not allowed to have expiration_datetime set.") + _("Professional education modes are not allowed to have expiration_datetime set.") ) mode_config = settings.COURSE_ENROLLMENT_MODES.get(self.mode_slug, {}) @@ -209,7 +209,7 @@ class CourseMode(models.Model): mode_display_name = mode_config.get('display_name', self.mode_slug) raise ValidationError( _( # lint-amnesty, pylint: disable=translation-of-non-string - u"The {course_mode} course mode has a minimum price of {min_price}. You must set a price greater than or equal to {min_price}.".format( # lint-amnesty, pylint: disable=line-too-long + "The {course_mode} course mode has a minimum price of {min_price}. You must set a price greater than or equal to {min_price}.".format( # lint-amnesty, pylint: disable=line-too-long course_mode=mode_display_name, min_price=min_price_for_mode ) ) @@ -222,7 +222,7 @@ class CourseMode(models.Model): if self.id is None: # If this model has no primary key at save time, it needs to be force-inserted. force_insert = True - super(CourseMode, self).save(force_insert, force_update, using) # lint-amnesty, pylint: disable=super-with-arguments + super().save(force_insert, force_update, using) @property def slug(self): @@ -304,7 +304,7 @@ class CourseMode(models.Model): mode for mode in modes if mode.expiration_datetime is None or mode.expiration_datetime >= now_dt ] - for course_id, modes in six.iteritems(all_modes) + for course_id, modes in all_modes.items() } return (all_modes, unexpired_modes) @@ -807,7 +807,7 @@ class CourseMode(models.Model): ) def __str__(self): - return u"{} : {}, min={}".format( + return "{} : {}, min={}".format( self.course_id, self.mode_slug, self.min_price ) @@ -888,7 +888,7 @@ class CourseModesArchive(models.Model): .. no_pii: """ - class Meta(object): + class Meta: app_label = "course_modes" # the course that this mode is attached to @@ -905,11 +905,11 @@ class CourseModesArchive(models.Model): min_price = models.IntegerField(default=0) # the suggested prices for this mode - suggested_prices = models.CharField(max_length=255, blank=True, default=u'', + suggested_prices = models.CharField(max_length=255, blank=True, default='', validators=[validate_comma_separated_integer_list]) # the currency these prices are in, using lower case ISO currency codes - currency = models.CharField(default=u"usd", max_length=8) + currency = models.CharField(default="usd", max_length=8) # turn this mode off after the given expiration date expiration_date = models.DateField(default=None, null=True, blank=True) @@ -924,7 +924,7 @@ class CourseModeExpirationConfig(ConfigurationModel): .. no_pii: """ - class Meta(object): + class Meta: app_label = "course_modes" verification_window = models.DurationField( @@ -936,4 +936,4 @@ class CourseModeExpirationConfig(ConfigurationModel): def __str__(self): """ Returns the unicode date of the verification window. """ - return six.text_type(self.verification_window) + return str(self.verification_window) diff --git a/common/djangoapps/course_modes/rest_api/serializers.py b/common/djangoapps/course_modes/rest_api/serializers.py index f3c73657a2a37cec0681e09b5f019b70a5d2060b..a0746f90d79d50e6b8dfa4ff5991674c4bed587c 100644 --- a/common/djangoapps/course_modes/rest_api/serializers.py +++ b/common/djangoapps/course_modes/rest_api/serializers.py @@ -29,7 +29,7 @@ class CourseModeSerializer(serializers.Serializer): sku = serializers.CharField(required=False) bulk_sku = serializers.CharField(required=False) - class Meta(object): + class Meta: # For disambiguating within the drf-yasg swagger schema ref_name = 'course_modes.CourseMode' diff --git a/common/djangoapps/course_modes/rest_api/v1/tests/test_views.py b/common/djangoapps/course_modes/rest_api/v1/tests/test_views.py index ecbf18360e2abfcd97a900b0118a0c1572445ed5..37aad8665162a631c2b574feac31b3a3a1351082 100644 --- a/common/djangoapps/course_modes/rest_api/v1/tests/test_views.py +++ b/common/djangoapps/course_modes/rest_api/v1/tests/test_views.py @@ -66,7 +66,7 @@ class CourseModesViewTestBase(AuthAndScopesTestMixin): cls.other_mode.delete() def setUp(self): - super(CourseModesViewTestBase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # overwrite self.student to be a staff member, since only staff # should be able to access the course_modes API endpoints. # This is needed to make a handful of tests inherited from AuthAndScopesTestMixin pass. @@ -89,7 +89,7 @@ class CourseModesViewTestBase(AuthAndScopesTestMixin): jwt_token = self._create_jwt_token(self.student, auth_type, include_me_filter=True) # include_me_filter=True means a JWT filter will require the username # of the requesting user to be in the requested URL - url = self.get_url(self.student) + '?username={}'.format(self.student.username) + url = self.get_url(self.student) + f'?username={self.student.username}' resp = self.get_response(AuthType.jwt, token=jwt_token, url=url) assert status.HTTP_200_OK == resp.status_code @@ -108,7 +108,7 @@ class TestCourseModesListViews(CourseModesViewTestBase, ModuleStoreTestCase, API Required method to implement AuthAndScopesTestMixin. """ kwargs = { - 'course_id': text_type(course_id or self.course_key) + 'course_id': str(course_id or self.course_key) } return reverse(self.view_name, kwargs=kwargs) @@ -130,7 +130,7 @@ class TestCourseModesListViews(CourseModesViewTestBase, ModuleStoreTestCase, API actual_results = self._sorted_results(response) expected_results = [ { - 'course_id': text_type(self.course_key), + 'course_id': str(self.course_key), 'mode_slug': 'audit', 'mode_display_name': 'Audit', 'min_price': 0, @@ -142,7 +142,7 @@ class TestCourseModesListViews(CourseModesViewTestBase, ModuleStoreTestCase, API 'bulk_sku': None, }, { - 'course_id': text_type(self.course_key), + 'course_id': str(self.course_key), 'mode_slug': 'verified', 'mode_display_name': 'Verified', 'min_price': 25, @@ -165,7 +165,7 @@ class TestCourseModesListViews(CourseModesViewTestBase, ModuleStoreTestCase, API other_actual_results = self._sorted_results(other_response) other_expected_results = [ { - 'course_id': text_type(self.other_course_key), + 'course_id': str(self.other_course_key), 'mode_slug': 'other-audit', 'mode_display_name': 'Other Audit', 'min_price': 0, @@ -199,7 +199,7 @@ class TestCourseModesListViews(CourseModesViewTestBase, ModuleStoreTestCase, API url = self.get_url(course_id=self.course_key) request_payload = { - 'course_id': text_type(self.course_key), + 'course_id': str(self.course_key), 'mode_slug': 'masters', 'mode_display_name': 'Masters', 'currency': 'usd', @@ -220,7 +220,7 @@ class TestCourseModesListViews(CourseModesViewTestBase, ModuleStoreTestCase, API url = self.get_url(course_id=self.course_key) request_payload = { - 'course_id': text_type(self.course_key), + 'course_id': str(self.course_key), 'mode_slug': 'phd', } @@ -252,7 +252,7 @@ class TestCourseModesDetailViews(CourseModesViewTestBase, APITestCase): Required method to implement AuthAndScopesTestMixin. """ kwargs = { - 'course_id': text_type(course_id or self.course_key), + 'course_id': str(course_id or self.course_key), 'mode_slug': mode_slug or 'audit', } return reverse(self.view_name, kwargs=kwargs) @@ -282,7 +282,7 @@ class TestCourseModesDetailViews(CourseModesViewTestBase, APITestCase): assert status.HTTP_200_OK == response.status_code actual_data = dict(response.data) expected_data = { - 'course_id': text_type(self.course_key), + 'course_id': str(self.course_key), 'mode_slug': 'audit', 'mode_display_name': 'Audit', 'min_price': 0, diff --git a/common/djangoapps/course_modes/rest_api/v1/urls.py b/common/djangoapps/course_modes/rest_api/v1/urls.py index a95e5de5aaaac08c311610397dc35666a224bb85..61026998401268669e8ee768c58ad29263d9de6f 100644 --- a/common/djangoapps/course_modes/rest_api/v1/urls.py +++ b/common/djangoapps/course_modes/rest_api/v1/urls.py @@ -12,12 +12,12 @@ app_name = 'v1' urlpatterns = [ url( - r'^courses/{course_id}/$'.format(course_id=settings.COURSE_ID_PATTERN), + fr'^courses/{settings.COURSE_ID_PATTERN}/$', views.CourseModesView.as_view(), name='course_modes_list' ), url( - r'^courses/{course_id}/(?P<mode_slug>.*)$'.format(course_id=settings.COURSE_ID_PATTERN), + fr'^courses/{settings.COURSE_ID_PATTERN}/(?P<mode_slug>.*)$', views.CourseModesDetailView.as_view(), name='course_modes_detail' ), diff --git a/common/djangoapps/course_modes/rest_api/v1/views.py b/common/djangoapps/course_modes/rest_api/v1/views.py index caeebb7097cf2e2349da94b253de2aee65e7a4cf..7c37d8596de8df43e263bae1df2223a3e8e1497b 100644 --- a/common/djangoapps/course_modes/rest_api/v1/views.py +++ b/common/djangoapps/course_modes/rest_api/v1/views.py @@ -22,7 +22,7 @@ from openedx.core.lib.api.parsers import MergePatchParser log = logging.getLogger(__name__) -class CourseModesMixin(object): +class CourseModesMixin: """ A base class for course modes views that specifies authentication, permissions, serialization, pagination, and the base queryset. diff --git a/common/djangoapps/course_modes/tests/factories.py b/common/djangoapps/course_modes/tests/factories.py index c19e027d6b5f7cced7571944734584dd19d6de80..624189690cf4818849cb1013079cd3ba20bb2032 100644 --- a/common/djangoapps/course_modes/tests/factories.py +++ b/common/djangoapps/course_modes/tests/factories.py @@ -17,7 +17,7 @@ from openedx.core.djangoapps.content.course_overviews.tests.factories import Cou # Factories are self documenting class CourseModeFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing-class-docstring - class Meta(object): + class Meta: model = CourseMode mode_slug = CourseMode.DEFAULT_MODE_SLUG @@ -38,7 +38,7 @@ class CourseModeFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=mi course_overview = None course_kwargs.setdefault('id', course_id) if course_id is not None: - if isinstance(course_id, six.string_types): + if isinstance(course_id, str): course_id = CourseKey.from_string(course_id) course_kwargs['id'] = course_id try: @@ -63,4 +63,4 @@ class CourseModeFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=mi @lazy_attribute def mode_display_name(self): - return '{0} course'.format(self.mode_slug) + return f'{self.mode_slug} course' diff --git a/common/djangoapps/course_modes/tests/test_admin.py b/common/djangoapps/course_modes/tests/test_admin.py index 2f42e4d93ca15c92fad844c22af3b23d884060ec..f04be6d51a5cf3ac635084904aaa769056e5e850 100644 --- a/common/djangoapps/course_modes/tests/test_admin.py +++ b/common/djangoapps/course_modes/tests/test_admin.py @@ -47,7 +47,7 @@ class AdminCourseModePageTest(ModuleStoreTestCase): CourseOverview.load_from_module_store(course.id) data = { - 'course': six.text_type(course.id), + 'course': str(course.id), 'mode_slug': 'verified', 'mode_display_name': 'verified', 'min_price': 10, @@ -91,7 +91,7 @@ class AdminCourseModeFormTest(ModuleStoreTestCase): """ Create a test course. """ - super(AdminCourseModeFormTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create() CourseOverview.load_from_module_store(self.course.id) @@ -199,7 +199,7 @@ class AdminCourseModeFormTest(ModuleStoreTestCase): mode_slug=mode, ) return CourseModeForm({ - "course": six.text_type(self.course.id), + "course": str(self.course.id), "mode_slug": mode, "mode_display_name": mode, "_expiration_datetime": upgrade_deadline, diff --git a/common/djangoapps/course_modes/tests/test_models.py b/common/djangoapps/course_modes/tests/test_models.py index f915f21866917b2a911468fa0d0b17a92af2f801..7279166929ecd73b576719aef3f39d2537d0991e 100644 --- a/common/djangoapps/course_modes/tests/test_models.py +++ b/common/djangoapps/course_modes/tests/test_models.py @@ -8,18 +8,21 @@ Replace this with more appropriate tests for your application. import itertools from datetime import timedelta +from unittest.mock import patch import ddt from django.core.exceptions import ValidationError from django.test import TestCase, override_settings from django.utils.timezone import now -from mock import patch from opaque_keys.edx.locator import CourseLocator -import six -from six.moves import zip from common.djangoapps.course_modes.helpers import enrollment_mode_display -from common.djangoapps.course_modes.models import CourseMode, Mode, get_cosmetic_display_price, invalidate_course_mode_cache # lint-amnesty, pylint: disable=line-too-long +from common.djangoapps.course_modes.models import ( # lint-amnesty, pylint: disable=line-too-long + CourseMode, + Mode, + get_cosmetic_display_price, + invalidate_course_mode_cache +) from common.djangoapps.course_modes.tests.factories import CourseModeFactory from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase @@ -38,12 +41,12 @@ class CourseModeModelTest(TestCase): } def setUp(self): - super(CourseModeModelTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course_key = CourseLocator('Test', 'TestCourse', 'TestCourseRun') CourseMode.objects.all().delete() def tearDown(self): - super(CourseModeModelTest, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments + super().tearDown() invalidate_course_mode_cache(sender=None) def create_mode( @@ -92,7 +95,7 @@ class CourseModeModelTest(TestCase): self.create_mode('verified', 'Verified Certificate', 10) modes = CourseMode.modes_for_course(self.course_key) - mode = Mode(u'verified', u'Verified Certificate', 10, '', 'usd', None, None, None, None) + mode = Mode('verified', 'Verified Certificate', 10, '', 'usd', None, None, None, None) assert [mode] == modes modes_dict = CourseMode.modes_for_course_dict(self.course_key) @@ -103,16 +106,16 @@ class CourseModeModelTest(TestCase): """ Finding the modes when there's multiple modes """ - mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None, None, None) - mode2 = Mode(u'verified', u'Verified Certificate', 10, '', 'usd', None, None, None, None) + mode1 = Mode('honor', 'Honor Code Certificate', 0, '', 'usd', None, None, None, None) + mode2 = Mode('verified', 'Verified Certificate', 10, '', 'usd', None, None, None, None) set_modes = [mode1, mode2] for mode in set_modes: self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices) modes = CourseMode.modes_for_course(self.course_key) assert modes == set_modes - assert mode1 == CourseMode.mode_for_course(self.course_key, u'honor') - assert mode2 == CourseMode.mode_for_course(self.course_key, u'verified') + assert mode1 == CourseMode.mode_for_course(self.course_key, 'honor') + assert mode2 == CourseMode.mode_for_course(self.course_key, 'verified') assert CourseMode.mode_for_course(self.course_key, 'DNE') is None def test_min_course_price_for_currency(self): @@ -123,9 +126,9 @@ class CourseModeModelTest(TestCase): assert 0 == CourseMode.min_course_price_for_currency(self.course_key, 'usd') # create some modes - mode1 = Mode(u'honor', u'Honor Code Certificate', 10, '', 'usd', None, None, None, None) - mode2 = Mode(u'verified', u'Verified Certificate', 20, '', 'usd', None, None, None, None) - mode3 = Mode(u'honor', u'Honor Code Certificate', 80, '', 'cny', None, None, None, None) + mode1 = Mode('honor', 'Honor Code Certificate', 10, '', 'usd', None, None, None, None) + mode2 = Mode('verified', 'Verified Certificate', 20, '', 'usd', None, None, None, None) + mode3 = Mode('honor', 'Honor Code Certificate', 80, '', 'cny', None, None, None, None) set_modes = [mode1, mode2, mode3] for mode in set_modes: self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices, mode.currency) @@ -140,7 +143,7 @@ class CourseModeModelTest(TestCase): modes = CourseMode.modes_for_course(self.course_key) assert [CourseMode.DEFAULT_MODE] == modes - mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None, None, None) + mode1 = Mode('honor', 'Honor Code Certificate', 0, '', 'usd', None, None, None, None) self.create_mode(mode1.slug, mode1.name, mode1.min_price, mode1.suggested_prices) modes = CourseMode.modes_for_course(self.course_key) assert [mode1] == modes @@ -149,8 +152,8 @@ class CourseModeModelTest(TestCase): expired_mode.expiration_datetime = expiration_datetime expired_mode.save() expired_mode_value = Mode( - u'verified', - u'Verified Certificate', + 'verified', + 'Verified Certificate', 10, '', 'usd', @@ -335,7 +338,7 @@ class CourseModeModelTest(TestCase): assert not is_error_expected, 'Expected a ValidationError to be thrown.' except ValidationError as exc: assert is_error_expected, 'Did not expect a ValidationError to be thrown.' - assert exc.messages == [u'Professional education modes are not allowed to have expiration_datetime set.'] + assert exc.messages == ['Professional education modes are not allowed to have expiration_datetime set.'] @ddt.data( ("verified", "verify_need_to_verify"), @@ -385,11 +388,11 @@ class CourseModeModelTest(TestCase): # Check the selectable modes, which should exclude credit selectable_modes = CourseMode.modes_for_course_dict(self.course_key) - six.assertCountEqual(self, list(selectable_modes.keys()), expected_selectable_modes) + self.assertCountEqual(list(selectable_modes.keys()), expected_selectable_modes) # When we get all unexpired modes, we should see credit as well all_modes = CourseMode.modes_for_course_dict(self.course_key, only_selectable=False) - six.assertCountEqual(self, list(all_modes.keys()), available_modes) + self.assertCountEqual(list(all_modes.keys()), available_modes) def _enrollment_display_modes_dicts(self, dict_type): """ diff --git a/common/djangoapps/course_modes/tests/test_signals.py b/common/djangoapps/course_modes/tests/test_signals.py index ff040659693972be381e61d4a50cc4635acb948c..d244f692b88314170481a21fdcfb9d06d2c13c0f 100644 --- a/common/djangoapps/course_modes/tests/test_signals.py +++ b/common/djangoapps/course_modes/tests/test_signals.py @@ -4,10 +4,10 @@ Unit tests for the course_mode signals from datetime import datetime, timedelta +from unittest.mock import patch import ddt from django.conf import settings -from mock import patch from pytz import UTC from common.djangoapps.course_modes.models import CourseMode @@ -25,7 +25,7 @@ class CourseModeSignalTest(ModuleStoreTestCase): """ def setUp(self): - super(CourseModeSignalTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.end = datetime.now(tz=UTC).replace(microsecond=0) + timedelta(days=7) self.course = CourseFactory.create(end=self.end) CourseMode.objects.all().delete() diff --git a/common/djangoapps/course_modes/tests/test_views.py b/common/djangoapps/course_modes/tests/test_views.py index 3eaaa462292326a79d0906a09e596e617a82728f..d60c1908916ef80f2c9a3581be95f3481feb5823 100644 --- a/common/djangoapps/course_modes/tests/test_views.py +++ b/common/djangoapps/course_modes/tests/test_views.py @@ -6,6 +6,7 @@ Tests for course_modes views. import decimal import unittest from datetime import datetime, timedelta +from unittest.mock import patch import ddt import freezegun @@ -14,20 +15,19 @@ import pytz import six from django.conf import settings from django.urls import reverse -from mock import patch from common.djangoapps.course_modes.models import CourseMode, Mode from common.djangoapps.course_modes.tests.factories import CourseModeFactory +from common.djangoapps.student.models import CourseEnrollment +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory +from common.djangoapps.util.testing import UrlResetMixin +from common.djangoapps.util.tests.mixins.discovery import CourseCatalogServiceMockMixin from lms.djangoapps.commerce.tests import test_utils as ecomm_test_utils from lms.djangoapps.commerce.tests.mocks import mock_payment_processors from lms.djangoapps.verify_student.services import IDVerificationService from openedx.core.djangoapps.catalog.tests.mixins import CatalogIntegrationMixin from openedx.core.djangoapps.embargo.test_utils import restrict_course from openedx.core.djangoapps.theming.tests.test_util import with_comprehensive_theme -from common.djangoapps.student.models import CourseEnrollment -from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory -from common.djangoapps.util.testing import UrlResetMixin -from common.djangoapps.util.tests.mixins.discovery import CourseCatalogServiceMockMixin from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -43,7 +43,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest @patch.dict(settings.FEATURES, {'MODE_CREATION_FOR_TESTING': True}) def setUp(self): - super(CourseModeViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() now = datetime.now(pytz.utc) day = timedelta(days=1) tomorrow = now + day @@ -88,7 +88,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest ) # Configure whether we're upgrading or not - url = reverse('course_modes_choose', args=[six.text_type(course.id)]) + url = reverse('course_modes_choose', args=[str(course.id)]) response = self.client.get(url) # Check whether we were correctly redirected @@ -115,7 +115,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest ) # Configure whether we're upgrading or not - url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) + url = reverse('course_modes_choose', args=[str(self.course.id)]) response = self.client.get(url) start_flow_url = IDVerificationService.get_verify_location(course_id=self.course.id) @@ -136,7 +136,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest user=self.user ) # Configure whether we're upgrading or not - url = reverse('course_modes_choose', args=[six.text_type(prof_course.id)]) + url = reverse('course_modes_choose', args=[str(prof_course.id)]) response = self.client.get(url) self.assertRedirects(response, '/test_basket/add/?sku=TEST', fetch_redirect_response=False) ecomm_test_utils.update_commerce_config(enabled=False) @@ -170,7 +170,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest # Verify that the prices render correctly response = self.client.get( - reverse('course_modes_choose', args=[six.text_type(self.course.id)]), + reverse('course_modes_choose', args=[str(self.course.id)]), follow=False, ) @@ -191,7 +191,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest # Check whether credit upsell is shown on the page # This should *only* be shown when a credit mode is available - url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) + url = reverse('course_modes_choose', args=[str(self.course.id)]) response = self.client.get(url) if show_upsell: @@ -247,7 +247,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest # Check whether congratulations message is shown on the page # This should *only* be shown when an enrollment exists - url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) + url = reverse('course_modes_choose', args=[str(self.course.id)]) response = self.client.get(url) if create_enrollment: @@ -261,7 +261,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=1) # Go to the "choose your track" page - choose_track_url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) + choose_track_url = reverse('course_modes_choose', args=[str(self.course.id)]) response = self.client.get(choose_track_url) # Since the only available track is professional ed, expect that @@ -274,7 +274,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest user=self.user, is_active=True, mode=mode, - course_id=six.text_type(self.course.id), + course_id=str(self.course.id), ) # Expect that this time we're redirected to the dashboard (since we're already registered) @@ -303,7 +303,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest CourseModeFactory.create(mode_slug=mode, course_id=self.course.id, min_price=min_price) # Choose the mode (POST request) - choose_track_url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) + choose_track_url = reverse('course_modes_choose', args=[str(self.course.id)]) response = self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[course_mode]) # Verify the redirect @@ -330,7 +330,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest assert is_active is None # Choose the audit mode (POST request) - choose_track_url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) + choose_track_url = reverse('course_modes_choose', args=[str(self.course.id)]) self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[audit_mode]) # Assert learner is enrolled in Audit track post-POST @@ -358,14 +358,14 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest CourseModeFactory.create(mode_slug='verified', course_id=self.course.id, min_price=1) # Choose the mode (POST request) - choose_track_url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) + choose_track_url = reverse('course_modes_choose', args=[str(self.course.id)]) self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE['verified']) # Expect that the contribution amount is stored in the user's session assert 'donation_for_course' in self.client.session - assert six.text_type(self.course.id) in self.client.session['donation_for_course'] + assert str(self.course.id) in self.client.session['donation_for_course'] - actual_amount = self.client.session['donation_for_course'][six.text_type(self.course.id)] + actual_amount = self.client.session['donation_for_course'][str(self.course.id)] expected_amount = decimal.Decimal(self.POST_PARAMS_FOR_COURSE_MODE['verified']['contribution']) assert actual_amount == expected_amount @@ -378,12 +378,12 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest # automatic enrollment params = { 'enrollment_action': 'enroll', - 'course_id': six.text_type(self.course.id) + 'course_id': str(self.course.id) } self.client.post(reverse('change_enrollment'), params) # Explicitly select the honor mode (POST request) - choose_track_url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) + choose_track_url = reverse('course_modes_choose', args=[str(self.course.id)]) self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE[CourseMode.DEFAULT_MODE_SLUG]) # Verify that the user's enrollment remains unchanged @@ -397,7 +397,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest CourseModeFactory.create(mode_slug=mode, course_id=self.course.id) # Choose an unsupported mode (POST request) - choose_track_url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) + choose_track_url = reverse('course_modes_choose', args=[str(self.course.id)]) response = self.client.post(choose_track_url, self.POST_PARAMS_FOR_COURSE_MODE['unsupported']) assert 400 == response.status_code @@ -405,20 +405,20 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') def test_default_mode_creation(self): # Hit the mode creation endpoint with no querystring params, to create an honor mode - url = reverse('create_mode', args=[six.text_type(self.course.id)]) + url = reverse('create_mode', args=[str(self.course.id)]) response = self.client.get(url) assert response.status_code == 200 - expected_mode = [Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None, None, None)] + expected_mode = [Mode('honor', 'Honor Code Certificate', 0, '', 'usd', None, None, None, None)] course_mode = CourseMode.modes_for_course(self.course.id) assert course_mode == expected_mode @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @ddt.data( - (u'verified', u'Verified Certificate', 10, '10,20,30', 'usd'), - (u'professional', u'Professional Education', 100, '100,200', 'usd'), + ('verified', 'Verified Certificate', 10, '10,20,30', 'usd'), + ('professional', 'Professional Education', 100, '100,200', 'usd'), ) @ddt.unpack def test_verified_mode_creation(self, mode_slug, mode_display_name, min_price, suggested_prices, currency): @@ -429,7 +429,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest parameters['suggested_prices'] = suggested_prices parameters['currency'] = currency - url = reverse('create_mode', args=[six.text_type(self.course.id)]) + url = reverse('create_mode', args=[str(self.course.id)]) response = self.client.get(url, parameters) assert response.status_code == 200 @@ -454,23 +454,23 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') def test_multiple_mode_creation(self): # Create an honor mode - base_url = reverse('create_mode', args=[six.text_type(self.course.id)]) + base_url = reverse('create_mode', args=[str(self.course.id)]) self.client.get(base_url) # Excluding the currency parameter implicitly tests the mode creation endpoint's ability to # use default values when parameters are partially missing. parameters = {} - parameters['mode_slug'] = u'verified' - parameters['mode_display_name'] = u'Verified Certificate' + parameters['mode_slug'] = 'verified' + parameters['mode_display_name'] = 'Verified Certificate' parameters['min_price'] = 10 parameters['suggested_prices'] = '10,20' # Create a verified mode - url = reverse('create_mode', args=[six.text_type(self.course.id)]) + url = reverse('create_mode', args=[str(self.course.id)]) self.client.get(url, parameters) - honor_mode = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None, None, None) - verified_mode = Mode(u'verified', u'Verified Certificate', 10, '10,20', 'usd', None, None, None, None) + honor_mode = Mode('honor', 'Honor Code Certificate', 0, '', 'usd', None, None, None, None) + verified_mode = Mode('verified', 'Verified Certificate', 10, '10,20', 'usd', None, None, None, None) expected_modes = [honor_mode, verified_mode] course_modes = CourseMode.modes_for_course(self.course.id) @@ -485,7 +485,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest CourseModeFactory.create(mode_slug=mode, course_id=self.course.id) # Load the track selection page - url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) + url = reverse('course_modes_choose', args=[str(self.course.id)]) response = self.client.get(url) # Verify that the header navigation links are hidden for the edx.org version @@ -502,7 +502,7 @@ class CourseModeViewTest(CatalogIntegrationMixin, UrlResetMixin, ModuleStoreTest self.course.enrollment_end = datetime(2015, 1, 1) modulestore().update_item(self.course, self.user.id) - url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) + url = reverse('course_modes_choose', args=[str(self.course.id)]) response = self.client.get(url) # URL-encoded version of 1/1/15, 12:00 AM redirect_url = reverse('dashboard') + '?course_closed=1%2F1%2F15%2C+12%3A00+AM' @@ -517,7 +517,7 @@ class TrackSelectionEmbargoTest(UrlResetMixin, ModuleStoreTestCase): @patch.dict(settings.FEATURES, {'EMBARGO': True}) def setUp(self): - super(TrackSelectionEmbargoTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # Create a course and course modes self.course = CourseFactory.create() @@ -529,7 +529,7 @@ class TrackSelectionEmbargoTest(UrlResetMixin, ModuleStoreTestCase): self.client.login(username=self.user.username, password="edx") # Construct the URL for the track selection page - self.url = reverse('course_modes_choose', args=[six.text_type(self.course.id)]) + self.url = reverse('course_modes_choose', args=[str(self.course.id)]) @patch.dict(settings.FEATURES, {'EMBARGO': True}) def test_embargo_restrict(self): diff --git a/common/djangoapps/course_modes/urls.py b/common/djangoapps/course_modes/urls.py index 8e3937ef1417deb19f4ecc4d7ea5bee51ea306af..6337f51943458a2538129e04d5ac906b21dfb0a3 100644 --- a/common/djangoapps/course_modes/urls.py +++ b/common/djangoapps/course_modes/urls.py @@ -7,13 +7,13 @@ from django.conf.urls import url from common.djangoapps.course_modes import views urlpatterns = [ - url(r'^choose/{}/$'.format(settings.COURSE_ID_PATTERN), views.ChooseModeView.as_view(), name='course_modes_choose'), + url(fr'^choose/{settings.COURSE_ID_PATTERN}/$', views.ChooseModeView.as_view(), name='course_modes_choose'), ] # Enable verified mode creation if settings.FEATURES.get('MODE_CREATION_FOR_TESTING'): urlpatterns.append( - url(r'^create_mode/{}/$'.format(settings.COURSE_ID_PATTERN), + url(fr'^create_mode/{settings.COURSE_ID_PATTERN}/$', views.create_mode, name='create_mode'), ) diff --git a/common/djangoapps/course_modes/views.py b/common/djangoapps/course_modes/views.py index 389c5a59f72cdc03ffc80fec5597375cff8ead68..df7bd13bd5333aa0df16bf08e6003ab7e37abefd 100644 --- a/common/djangoapps/course_modes/views.py +++ b/common/djangoapps/course_modes/views.py @@ -64,7 +64,7 @@ class ChooseModeView(View): atomic() block is active, since that would break atomicity. """ - return super(ChooseModeView, self).dispatch(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + return super().dispatch(*args, **kwargs) @method_decorator(login_required) @method_decorator(transaction.atomic) @@ -136,13 +136,13 @@ class ChooseModeView(View): return redirect(reverse('dashboard')) donation_for_course = request.session.get("donation_for_course", {}) - chosen_price = donation_for_course.get(six.text_type(course_key), None) + chosen_price = donation_for_course.get(str(course_key), None) if CourseEnrollment.is_enrollment_closed(request.user, course): locale = to_locale(get_language()) enrollment_end_date = format_datetime(course.enrollment_end, 'short', locale=locale) params = six.moves.urllib.parse.urlencode({'course_closed': enrollment_end_date}) - return redirect('{0}?{1}'.format(reverse('dashboard'), params)) + return redirect('{}?{}'.format(reverse('dashboard'), params)) # When a credit mode is available, students will be given the option # to upgrade from a verified mode to a credit mode at the end of the course. @@ -156,7 +156,7 @@ class ChooseModeView(View): CourseMode.is_credit_mode(mode) for mode in CourseMode.modes_for_course(course_key, only_selectable=False) ) - course_id = text_type(course_key) + course_id = str(course_key) context = { "course_modes_choose_url": reverse( @@ -307,7 +307,7 @@ class ChooseModeView(View): return self.get(request, course_id, error=error_msg) donation_for_course = request.session.get("donation_for_course", {}) - donation_for_course[six.text_type(course_key)] = amount_value + donation_for_course[str(course_key)] = amount_value request.session["donation_for_course"] = donation_for_course verify_url = IDVerificationService.get_verify_location(course_id=course_key) @@ -358,16 +358,16 @@ def create_mode(request, course_id): Response """ PARAMETERS = { - 'mode_slug': u'honor', - 'mode_display_name': u'Honor Code Certificate', + 'mode_slug': 'honor', + 'mode_display_name': 'Honor Code Certificate', 'min_price': 0, - 'suggested_prices': u'', - 'currency': u'usd', + 'suggested_prices': '', + 'currency': 'usd', 'sku': None, } # Try pulling querystring parameters out of the request - for parameter, default in six.iteritems(PARAMETERS): + for parameter, default in PARAMETERS.items(): PARAMETERS[parameter] = request.GET.get(parameter, default) # Attempt to create the new mode for the given course